diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 4d104e09..a5295a3f 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -13,3 +13,8 @@ *= require font-awesome *= require_tree . */ + +/* Alpine.js x-cloak - hide elements until Alpine loads */ +[x-cloak] { + display: none !important; +} diff --git a/app/assets/stylesheets/currently-online.scss b/app/assets/stylesheets/currently-online.scss new file mode 100644 index 00000000..d2594d3e --- /dev/null +++ b/app/assets/stylesheets/currently-online.scss @@ -0,0 +1,217 @@ +// Currently Online Widget Styling +// A fixed position tab in bottom-right that expands to show online users + +.thredded--currently-online { + position: fixed; + bottom: 0; + right: 20px; + z-index: 1000; + background: white; + border: 1px solid #e5e7eb; + border-bottom: none; + border-radius: 8px 8px 0 0; + box-shadow: 0 -4px 6px -1px rgba(0, 0, 0, 0.1), 0 -2px 4px -1px rgba(0, 0, 0, 0.06); + transition: all 0.3s ease; + min-width: 250px; + max-width: 350px; + + // Collapsed state (default) + &[x-data] { + // This will be controlled by Alpine.js + } + + // Header (always visible) + header { + cursor: pointer; + padding: 12px 16px; + background: #3b82f6; // bg-notebook-blue + border-radius: 7px 7px 0 0; + user-select: none; + + &:hover { + background: #2563eb; // Slightly darker on hover + } + } + + .thredded--currently-online--title { + margin: 0; + font-size: 14px; + font-weight: 600; + color: white; + display: flex; + align-items: center; + justify-content: space-between; + + // Add count badge + &::after { + content: attr(data-count); + background: rgba(255, 255, 255, 0.2); + padding: 2px 8px; + border-radius: 12px; + font-size: 12px; + margin-left: 8px; + } + + // Expand/collapse indicator + &::before { + content: '▼'; + font-size: 10px; + margin-right: 8px; + transition: transform 0.3s ease; + display: inline-block; + } + + &.collapsed::before { + transform: rotate(-90deg); + } + } + + // User list container + .thredded--currently-online--users { + max-height: 0; + overflow: hidden; + transition: max-height 0.3s ease, padding 0.3s ease; + margin: 0; + padding: 0; + list-style: none; + background: white; + border-top: 1px solid #f3f4f6; + + &.expanded { + max-height: 400px; + overflow-y: auto; + padding: 8px 0; + } + } + + // Individual user item + .thredded--currently-online--user { + padding: 0; + margin: 0; + + a { + display: flex; + align-items: center; + padding: 8px 16px; + text-decoration: none; + color: #374151; + font-size: 14px; + transition: background-color 0.2s ease; + + &:hover { + background-color: #f9fafb; + color: #3b82f6; + } + } + } + + // User avatar + .thredded--currently-online--avatar { + width: 32px; + height: 32px; + border-radius: 50%; + margin-right: 12px; + border: 2px solid #10b981; + box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.2); + } + + // Online indicator dot + .thredded--currently-online--user a::after { + content: ''; + width: 8px; + height: 8px; + background: #10b981; + border-radius: 50%; + margin-left: auto; + animation: pulse 2s infinite; + } + + // Scrollbar styling for user list + .thredded--currently-online--users::-webkit-scrollbar { + width: 6px; + } + + .thredded--currently-online--users::-webkit-scrollbar-track { + background: #f3f4f6; + border-radius: 3px; + } + + .thredded--currently-online--users::-webkit-scrollbar-thumb { + background: #d1d5db; + border-radius: 3px; + + &:hover { + background: #9ca3af; + } + } +} + +// Pulse animation for online indicator +@keyframes pulse { + 0% { + box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7); + } + 70% { + box-shadow: 0 0 0 6px rgba(16, 185, 129, 0); + } + 100% { + box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); + } +} + +// Dark mode support +.dark .thredded--currently-online { + background: #1f2937; + border-color: #374151; + box-shadow: 0 -4px 6px -1px rgba(0, 0, 0, 0.3); + + header { + background: #1e40af; // Darker blue for dark mode + + &:hover { + background: #1e3a8a; // Even darker on hover + } + } + + .thredded--currently-online--users { + background: #1f2937; + border-top-color: #374151; + } + + .thredded--currently-online--user a { + color: #d1d5db; + + &:hover { + background-color: #111827; + color: #a78bfa; + } + } + + .thredded--currently-online--avatar { + border-color: #10b981; + } +} + +// Mobile responsiveness +@media (max-width: 640px) { + .thredded--currently-online { + right: 10px; + min-width: 160px; + max-width: 200px; + + .thredded--currently-online--title { + font-size: 13px; + } + + .thredded--currently-online--user a { + font-size: 13px; + padding: 6px 12px; + } + + .thredded--currently-online--avatar { + width: 28px; + height: 28px; + margin-right: 10px; + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/forum-messageboards.scss b/app/assets/stylesheets/forum-messageboards.scss new file mode 100644 index 00000000..e95a12bf --- /dev/null +++ b/app/assets/stylesheets/forum-messageboards.scss @@ -0,0 +1,268 @@ +// Forum Messageboards - Professional Literary Design +// Minimal, sophisticated design for professional and indie authors + +// Messageboard card - clean manuscript aesthetic +.messageboard-card { + position: relative; + background: #ffffff; + border: 1px solid #e5e7eb; + border-radius: 3px; + transition: all 0.15s ease; + overflow: hidden; + + // Subtle depth indicator - hint at stack without being literal + border-bottom: 2px solid #e5e7eb; + + // Clean, professional shadow + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06); + + // Refined hover state - subtle elevation + &:hover { + transform: translateY(-1px); + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + border-bottom-color: #d1d5db; + + h3 { + color: #3b82f6; // notebook-blue on hover for title + } + } + + // Active/focus state + &:focus-within { + outline: 2px solid #3b82f6; + outline-offset: -1px; + } +} + +// Compact, professional spacing +.messageboard-compact { + // Header section + .messageboard-header { + padding: 0.875rem; // 14px + + h3 { + font-size: 0.9375rem; // 15px + line-height: 1.25rem; + font-weight: 600; + margin: 0; + color: #111827; + transition: color 0.15s ease; + letter-spacing: -0.01em; + } + } + + // Description - subtle and professional + .messageboard-description { + font-size: 0.8125rem; // 13px + line-height: 1.25rem; + margin: 0.375rem 0; + color: #6b7280; + + // Single line with ellipsis + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + // Stats section - minimal + .messageboard-stats { + font-size: 0.75rem; // 12px + color: #9ca3af; + margin-top: 0.625rem; + font-weight: 500; + letter-spacing: 0.025em; + + .material-icons { + font-size: 0.875rem; // 14px + vertical-align: text-bottom; + opacity: 0.7; + } + } + + // Footer - subtle separator + .messageboard-footer { + padding: 0.625rem 0.875rem; // 10px 14px + background: #fafafa; + border-top: 1px solid #f3f4f6; + font-size: 0.75rem; // 12px + color: #6b7280; + + span { + font-weight: 500; + } + } +} + +// Group titles - typography-focused +.messageboard-group-title { + margin: 1.25rem 0 0.875rem 0; + font-size: 0.75rem; // 12px + font-weight: 700; + color: #6b7280; + text-transform: uppercase; + letter-spacing: 0.05em; + + // Remove decorative line - let typography do the work + &::before { + display: none; + } + + // First group spacing + &:first-child { + margin-top: 0; + } + + a { + color: inherit; + text-decoration: none; + + &:hover { + color: #4b5563; + } + } +} + +// Grid with professional spacing +.messageboards-grid { + gap: 1rem; // 16px - gives breathing room + + @media (min-width: 768px) { + gap: 1.25rem; // 20px on larger screens + } +} + +// Locked indicator - subtle and inline +.messageboard-locked { + .messageboard-header h3 { + .material-icons { + font-size: 0.875rem; + opacity: 0.5; + vertical-align: middle; + margin-right: 0.25rem; + } + } +} + +// Unread badge - minimal +.messageboard-unread-badge { + padding: 0.125rem 0.5rem; + font-size: 0.6875rem; // 11px + font-weight: 600; + border-radius: 3px; + background: #f3f4f6; + color: #4b5563; + + // Blue for followed topics + &.followed { + background: #eff6ff; + color: #3b82f6; + } + + // Blue for new topics + &.new { + background: #eff6ff; + color: #2563eb; + } +} + +// Page header - clean and professional +.forum-page-header { + padding: 1.5rem 0 1rem; + border-bottom: 1px solid #f3f4f6; + margin-bottom: 1.5rem; + + h1 { + font-size: 1.75rem; // 28px + line-height: 2.25rem; + font-weight: 700; + letter-spacing: -0.025em; + color: #111827; + + .material-icons { + font-size: 1.75rem; + opacity: 0.8; + vertical-align: middle; + margin-right: 0.5rem; + } + } + + p { + font-size: 0.9375rem; // 15px + margin-top: 0.375rem; + color: #6b7280; + } +} + +// Dark mode - maintain professionalism +.dark { + .messageboard-card { + background: #1f2937; + border-color: #374151; + border-bottom-color: #374151; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + + &:hover { + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.4); + border-bottom-color: #4b5563; + + h3 { + color: #a78bfa; + } + } + } + + .messageboard-compact { + .messageboard-header h3 { + color: #f3f4f6; + } + + .messageboard-description { + color: #9ca3af; + } + + .messageboard-stats { + color: #6b7280; + } + + .messageboard-footer { + background: #111827; + border-top-color: #374151; + color: #9ca3af; + } + } + + .messageboard-group-title { + color: #9ca3af; + + a:hover { + color: #d1d5db; + } + } + + .messageboard-unread-badge { + background: #374151; + color: #d1d5db; + + &.followed { + background: rgba(167, 139, 250, 0.1); + color: #a78bfa; + } + + &.new { + background: rgba(59, 130, 246, 0.1); + color: #60a5fa; + } + } + + .forum-page-header { + border-bottom-color: #374151; + + h1 { + color: #f3f4f6; + } + + p { + color: #9ca3af; + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/forum-navigation.scss b/app/assets/stylesheets/forum-navigation.scss new file mode 100644 index 00000000..f20cff6f --- /dev/null +++ b/app/assets/stylesheets/forum-navigation.scss @@ -0,0 +1,57 @@ +// Forum Navigation Styling +// This file contains minimal styling for forum navigation elements +// that can't be easily styled with Tailwind classes + +.thredded-nav { + // Ensure nav items are properly contained + ul { + display: flex; + align-items: center; + height: 100%; + margin: 0; + padding: 0; + list-style: none; + } + + li { + display: flex; + align-items: center; + height: 100%; + margin: 0; + } + + // Style for navigation icons + .material-icons { + font-size: 18px; + vertical-align: middle; + } + + // Ensure links fill their containers + a { + display: flex; + align-items: center; + height: 100%; + text-decoration: none; + } + + // Current page indicator + .thredded--is-current { + background-color: rgba(59, 130, 246, 0.1); // blue-50 equivalent + border-bottom: 2px solid rgb(59, 130, 246); // blue-500 + } +} + +// Ensure the thredded container doesn't overflow +#thredded--container { + max-width: 100%; +} + +.thredded--container { + max-width: 100%; +} + +// Forum post content sizing +.thredded--post--content { + font-size: 14px; + line-height: 1.6; +} \ No newline at end of file diff --git a/app/assets/stylesheets/forum-topics.scss b/app/assets/stylesheets/forum-topics.scss new file mode 100644 index 00000000..3c3d664d --- /dev/null +++ b/app/assets/stylesheets/forum-topics.scss @@ -0,0 +1,415 @@ +// Forum Topics - Collapsible New Discussion Form +// Progressive disclosure pattern for starting new discussions + +// New topic form container +.thredded--new-topic-form { + position: relative; + margin-bottom: 1.5rem; + transition: all 0.3s ease; + + // Wrapper for Alpine.js states + &[x-data] { + // Initial collapsed state styles handled by Alpine + } +} + +// Collapsed state - single input field +.new-topic-collapsed { + position: relative; + + .collapsed-input { + width: 100%; + padding: 1.5rem 1rem 1.5rem 2.75rem; + font-size: 0.9375rem; + background: #ffffff; + border: 1px solid #e5e7eb; + border-radius: 6px; + cursor: text; + transition: all 0.2s ease; + color: #6b7280; + + &:hover { + border-color: #d1d5db; + background: #fafafa; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + } + + &:focus { + outline: none; + border-color: #3b82f6; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); + color: #111827; + } + + // Icon + &::before { + content: ''; + position: absolute; + left: 1rem; + top: 50%; + transform: translateY(-50%); + width: 1.25rem; + height: 1.25rem; + background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M12 5v14M5 12h14'/%3E%3C/svg%3E") no-repeat center; + background-size: contain; + } + } + + // Fake placeholder + .collapsed-placeholder { + position: absolute; + left: 2.75rem; + top: 50%; + transform: translateY(-50%); + color: #9ca3af; + pointer-events: none; + transition: opacity 0.2s ease; + } +} + +// Expanded state - full form +.new-topic-expanded { + background: #ffffff; + border: 1px solid #e5e7eb; + border-radius: 8px; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + overflow: hidden; + + // Form header + .form-header { + padding: 1rem 1.25rem 0.75rem; + border-bottom: 1px solid #f3f4f6; + background: #fafafa; + + .form-title { + font-size: 0.875rem; + font-weight: 600; + color: #374151; + display: flex; + align-items: center; + + .material-icons { + font-size: 1rem; + margin-right: 0.5rem; + opacity: 0.7; + } + } + } + + // Form content area + .form-content { + padding: 1.25rem; + } + + // Override thredded's default form list styles + .thredded--form-list { + margin: 0; + padding: 0; + list-style: none; + + li { + margin-bottom: 1rem; + + &:last-child { + margin-bottom: 0; + } + } + + // Title field + li.title { + input[type="text"] { + width: 100%; + padding: 0.625rem 0.875rem; + font-size: 1rem; + border: 1px solid #d1d5db; + border-radius: 4px; + transition: all 0.15s ease; + + &:focus { + outline: none; + border-color: #3b82f6; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); + } + + &::placeholder { + color: #9ca3af; + } + } + + label { + display: block; + font-size: 0.8125rem; + font-weight: 500; + color: #4b5563; + margin-bottom: 0.375rem; + } + } + + // Content textarea + textarea { + width: 100%; + min-height: 120px; + padding: 0.625rem 0.875rem; + font-size: 0.9375rem; + border: 1px solid #d1d5db; + border-radius: 4px; + resize: vertical; + transition: all 0.15s ease; + font-family: inherit; + + &:focus { + outline: none; + border-color: #3b82f6; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); + min-height: 150px; + } + + &::placeholder { + color: #9ca3af; + } + } + + // Category select + li.category { + select { + width: 100%; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + border: 1px solid #d1d5db; + border-radius: 4px; + background: white; + cursor: pointer; + + &:focus { + outline: none; + border-color: #3b82f6; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); + } + } + } + } + + // Form actions + .form-actions { + padding: 1rem 1.25rem; + background: #fafafa; + border-top: 1px solid #f3f4f6; + display: flex; + justify-content: space-between; + align-items: center; + + .left-actions { + display: flex; + gap: 0.5rem; + } + + .right-actions { + display: flex; + gap: 0.5rem; + } + + // Buttons + .thredded--form--submit { + padding: 0.5rem 1.25rem; + font-size: 0.875rem; + font-weight: 500; + border-radius: 4px; + border: none; + cursor: pointer; + transition: all 0.15s ease; + background: #3b82f6; + color: white; + + &:hover:not(:disabled) { + background: #2563eb; + } + + &:focus { + outline: none; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3); + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } + } + + .btn-cancel { + padding: 0.5rem 1rem; + font-size: 0.875rem; + font-weight: 500; + border-radius: 4px; + border: 1px solid #d1d5db; + background: white; + color: #6b7280; + cursor: pointer; + transition: all 0.15s ease; + + &:hover { + background: #f9fafb; + border-color: #9ca3af; + } + + &:focus { + outline: none; + box-shadow: 0 0 0 3px rgba(107, 114, 128, 0.1); + } + } + + .btn-preview { + padding: 0.5rem 1rem; + font-size: 0.875rem; + font-weight: 500; + border-radius: 4px; + border: 1px solid #e5e7eb; + background: white; + color: #6b7280; + cursor: pointer; + transition: all 0.15s ease; + display: flex; + align-items: center; + + .material-icons { + font-size: 1rem; + margin-right: 0.25rem; + } + + &:hover { + background: #f9fafb; + } + + &.active { + background: #eff6ff; + border-color: #3b82f6; + color: #2563eb; + } + } + } +} + +// Preview area +.thredded--preview-area { + margin: 1rem 0; + padding: 1rem; + background: #f9fafb; + border: 1px solid #e5e7eb; + border-radius: 4px; + min-height: 100px; + + &:empty::before { + content: 'Preview will appear here...'; + color: #9ca3af; + font-style: italic; + } +} + +// Transition classes for smooth animations +.form-expand-enter { + opacity: 0; + transform: translateY(-10px); +} + +.form-expand-enter-active { + opacity: 1; + transform: translateY(0); + transition: all 0.3s ease; +} + +.form-expand-leave { + opacity: 1; + transform: translateY(0); +} + +.form-expand-leave-active { + opacity: 0; + transform: translateY(-10px); + transition: all 0.2s ease; +} + +// Dark mode support +.dark { + .new-topic-collapsed { + .collapsed-input { + background: #1f2937; + border-color: #374151; + color: #9ca3af; + + &:hover { + background: #111827; + border-color: #4b5563; + } + + &:focus { + border-color: #3b82f6; + color: #f3f4f6; + } + } + + .collapsed-placeholder { + color: #6b7280; + } + } + + .new-topic-expanded { + background: #1f2937; + border-color: #374151; + + .form-header { + background: #111827; + border-bottom-color: #374151; + + .form-title { + color: #d1d5db; + } + } + + .thredded--form-list { + input[type="text"], + textarea, + select { + background: #111827; + border-color: #374151; + color: #f3f4f6; + + &:focus { + border-color: #3b82f6; + } + + &::placeholder { + color: #6b7280; + } + } + + label { + color: #9ca3af; + } + } + + .form-actions { + background: #111827; + border-top-color: #374151; + + .btn-cancel, + .btn-preview { + background: #1f2937; + border-color: #374151; + color: #9ca3af; + + &:hover { + background: #374151; + } + } + } + } + + .thredded--preview-area { + background: #111827; + border-color: #374151; + color: #d1d5db; + + &:empty::before { + color: #6b7280; + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/moderation.scss b/app/assets/stylesheets/moderation.scss new file mode 100644 index 00000000..8a6bb2d2 --- /dev/null +++ b/app/assets/stylesheets/moderation.scss @@ -0,0 +1,1483 @@ +// Moderation Dashboard Styling +// Modern admin interface for forum moderation + +// Main moderation container +.thredded--pending-moderation, +.thredded--moderation-history, +.thredded--moderation-activity, +.thredded--moderation-users { + // Override default spacing + .thredded--main-section { + padding: 0; + } +} + +// Moderation Navigation - Tab-style design +.thredded--moderation-navigation { + background: white; + border-bottom: 2px solid #e5e7eb; + padding: 0 1.5rem; + margin-bottom: 2rem; + + .thredded--moderation-navigation--items { + display: flex; + gap: 2rem; + margin: 0; + padding: 0; + list-style: none; + + .thredded--moderation-navigation--item { + position: relative; + + a { + display: block; + padding: 1rem 0; + color: #6b7280; + text-decoration: none; + font-weight: 500; + transition: all 0.15s ease; + border-bottom: 3px solid transparent; + + &:hover { + color: #2196F3; + } + + // Active tab indicator + &.active, + &[aria-current="page"] { + color: #2196F3; + border-bottom-color: #2196F3; + } + } + } + } + + // User search form in nav + form { + position: absolute; + right: 1.5rem; + top: 0.75rem; + + input[type="search"] { + padding: 0.5rem 1rem; + border: 1px solid #e5e7eb; + border-radius: 6px; + font-size: 0.875rem; + width: 200px; + transition: all 0.15s ease; + + &:focus { + outline: none; + border-color: #2196F3; + box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1); + width: 250px; + } + + &::placeholder { + color: #9ca3af; + } + } + } +} + +// Moderation stats dashboard +.moderation-dashboard { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1.5rem; + margin-bottom: 2rem; + + .stat-card { + background: white; + border-radius: 8px; + padding: 1.5rem; + border: 1px solid #e5e7eb; + transition: all 0.15s ease; + + &:hover { + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05); + transform: translateY(-2px); + } + + .stat-icon { + width: 48px; + height: 48px; + border-radius: 12px; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 1rem; + + .material-icons { + font-size: 24px; + } + + &.pending { + background: #fef3c7; + color: #f59e0b; + } + + &.approved { + background: #d1fae5; + color: #10b981; + } + + &.blocked { + background: #fee2e2; + color: #ef4444; + } + + &.users { + background: #ddd6fe; + color: #8b5cf6; + } + } + + .stat-value { + font-size: 2rem; + font-weight: 700; + color: #111827; + margin-bottom: 0.25rem; + } + + .stat-label { + font-size: 0.875rem; + color: #6b7280; + text-transform: uppercase; + letter-spacing: 0.05em; + } + + .stat-change { + margin-top: 0.5rem; + font-size: 0.8125rem; + + &.positive { + color: #10b981; + + &::before { + content: '↑ '; + } + } + + &.negative { + color: #ef4444; + + &::before { + content: '↓ '; + } + } + } + } +} + +// Moderated posts list +.moderation-posts { + background: white; + border-radius: 8px; + border: 1px solid #e5e7eb; + overflow: hidden; + + .moderation-posts-header { + padding: 1.25rem 1.5rem; + background: #f9fafb; + border-bottom: 1px solid #e5e7eb; + display: flex; + justify-content: space-between; + align-items: center; + + h3 { + margin: 0; + font-size: 1.125rem; + font-weight: 600; + color: #111827; + display: flex; + align-items: center; + + .material-icons { + margin-right: 0.5rem; + color: #6b7280; + } + } + + .filter-buttons { + display: flex; + gap: 0.5rem; + + button { + padding: 0.375rem 0.75rem; + border: 1px solid #e5e7eb; + background: white; + border-radius: 6px; + font-size: 0.8125rem; + color: #6b7280; + cursor: pointer; + transition: all 0.15s ease; + + &:hover { + background: #f9fafb; + } + + &.active { + background: #2196F3; + color: white; + border-color: #2196F3; + } + } + } + } + + .moderation-post { + border-bottom: 1px solid #f3f4f6; + padding: 1.5rem; + transition: background 0.15s ease; + + &:hover { + background: #fafbfc; + } + + &:last-child { + border-bottom: none; + } + + .post-header { + display: flex; + justify-content: space-between; + align-items: start; + margin-bottom: 1rem; + + .post-meta { + display: flex; + align-items: center; + gap: 1rem; + + .user-avatar { + width: 40px; + height: 40px; + border-radius: 50%; + border: 2px solid #e5e7eb; + } + + .user-info { + .username { + font-weight: 600; + color: #111827; + display: block; + margin-bottom: 0.125rem; + } + + .post-time { + font-size: 0.8125rem; + color: #6b7280; + + a { + color: inherit; + text-decoration: none; + + &:hover { + color: #2196F3; + } + } + } + } + } + + .post-status { + padding: 0.25rem 0.75rem; + border-radius: 16px; + font-size: 0.75rem; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.05em; + + &.pending { + background: #fef3c7; + color: #92400e; + } + + &.approved { + background: #d1fae5; + color: #065f46; + } + + &.blocked { + background: #fee2e2; + color: #991b1b; + } + } + } + + .post-content { + margin: 1rem 0; + padding-left: 3.25rem; + + .content-preview { + color: #374151; + line-height: 1.6; + max-height: 4.8em; + overflow: hidden; + position: relative; + + &.expanded { + max-height: none; + } + + &::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 2rem; + background: linear-gradient(transparent, white); + } + + &.expanded::after { + display: none; + } + } + + .expand-button { + margin-top: 0.5rem; + color: #2196F3; + font-size: 0.875rem; + cursor: pointer; + + &:hover { + text-decoration: underline; + } + } + } + + .post-actions { + padding-left: 3.25rem; + display: flex; + gap: 1rem; + + button { + padding: 0.5rem 1rem; + border-radius: 6px; + font-size: 0.875rem; + font-weight: 500; + cursor: pointer; + transition: all 0.15s ease; + display: flex; + align-items: center; + gap: 0.375rem; + + .material-icons { + font-size: 16px; + } + + &.approve-btn { + background: #10b981; + color: white; + border: 1px solid #10b981; + + &:hover { + background: #059669; + border-color: #059669; + } + } + + &.block-btn { + background: white; + color: #ef4444; + border: 1px solid #ef4444; + + &:hover { + background: #fee2e2; + } + } + + &.more-btn { + background: white; + color: #6b7280; + border: 1px solid #e5e7eb; + + &:hover { + background: #f9fafb; + } + } + } + } + } +} + +// Empty state +.thredded--empty { + text-align: center; + padding: 3rem 1.5rem; + background: white; + border-radius: 8px; + border: 1px solid #e5e7eb; + + .thredded--empty--title { + color: #111827; + font-size: 1.25rem; + font-weight: 600; + margin-bottom: 0.5rem; + } + + p { + color: #6b7280; + max-width: 400px; + margin: 0 auto; + } + + .empty-icon { + width: 80px; + height: 80px; + margin: 0 auto 1.5rem; + background: #f3f4f6; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + + .material-icons { + font-size: 40px; + color: #9ca3af; + } + } +} + +// Moderation notice banner +.thredded--moderated-notice { + background: #f0fdf4; + border: 1px solid #86efac; + border-radius: 8px; + padding: 1rem 1.5rem; + margin-bottom: 1.5rem; + display: flex; + align-items: center; + gap: 1rem; + + .material-icons { + color: #10b981; + font-size: 20px; + } + + .notice-content { + flex: 1; + + .notice-title { + font-weight: 600; + color: #065f46; + margin-bottom: 0.25rem; + } + + .notice-text { + font-size: 0.875rem; + color: #047857; + } + } + + .notice-dismiss { + padding: 0.25rem; + background: transparent; + border: none; + cursor: pointer; + color: #10b981; + transition: opacity 0.15s ease; + + &:hover { + opacity: 0.7; + } + } +} + +// Moderation History Page +.moderation-history-header { + background: white; + border-radius: 8px; + border: 1px solid #e5e7eb; + padding: 1.5rem; + margin-bottom: 2rem; + + .history-title { + display: flex; + align-items: center; + margin-bottom: 1.5rem; + + .material-icons { + font-size: 28px; + color: #6b7280; + margin-right: 0.75rem; + } + + h2 { + margin: 0; + font-size: 1.5rem; + font-weight: 600; + color: #111827; + } + } + + .history-filters { + display: flex; + gap: 1.5rem; + flex-wrap: wrap; + + .filter-group { + display: flex; + align-items: center; + gap: 0.5rem; + + label { + font-size: 0.875rem; + font-weight: 500; + color: #6b7280; + } + + .filter-select { + padding: 0.5rem 2rem 0.5rem 0.75rem; + border: 1px solid #e5e7eb; + border-radius: 6px; + font-size: 0.875rem; + color: #374151; + background: white; + background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right 0.5rem center; + background-size: 1rem; + appearance: none; + cursor: pointer; + transition: all 0.15s ease; + + &:focus { + outline: none; + border-color: #2196F3; + box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1); + } + } + } + } +} + +// Timeline Layout +.moderation-timeline { + position: relative; + padding-left: 3rem; + + // Vertical line + &::before { + content: ''; + position: absolute; + left: 1.25rem; + top: 0; + bottom: 0; + width: 2px; + background: #e5e7eb; + } + + .timeline-item { + position: relative; + margin-bottom: 2rem; + + &:last-child { + margin-bottom: 0; + } + + // Timeline marker dot + .timeline-marker { + position: absolute; + left: -2rem; + top: 0.5rem; + width: 2.5rem; + height: 2.5rem; + border-radius: 50%; + background: white; + border: 2px solid #e5e7eb; + display: flex; + align-items: center; + justify-content: center; + z-index: 1; + + .material-icons { + font-size: 20px; + } + } + + &.approved .timeline-marker { + border-color: #10b981; + background: #ecfdf5; + + .material-icons { + color: #10b981; + } + } + + &.blocked .timeline-marker { + border-color: #ef4444; + background: #fef2f2; + + .material-icons { + color: #ef4444; + } + } + + // Timeline content card + .timeline-content { + background: white; + border: 1px solid #e5e7eb; + border-radius: 8px; + overflow: hidden; + transition: all 0.15s ease; + + &:hover { + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05); + } + + .action-header { + padding: 1rem 1.25rem; + background: #f9fafb; + border-bottom: 1px solid #e5e7eb; + display: flex; + justify-content: space-between; + align-items: center; + + .action-info { + display: flex; + align-items: center; + gap: 0.75rem; + + .action-type { + padding: 0.25rem 0.625rem; + border-radius: 12px; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + + &.approved { + background: #d1fae5; + color: #065f46; + } + + &.blocked { + background: #fee2e2; + color: #991b1b; + } + } + + .action-meta { + font-size: 0.875rem; + color: #6b7280; + + a { + color: #2196F3; + text-decoration: none; + font-weight: 500; + + &:hover { + text-decoration: underline; + } + } + + .separator { + margin: 0 0.375rem; + color: #d1d5db; + } + } + } + + .action-links { + .view-post-link { + display: flex; + align-items: center; + gap: 0.375rem; + padding: 0.375rem 0.75rem; + border: 1px solid #e5e7eb; + border-radius: 6px; + font-size: 0.8125rem; + color: #6b7280; + text-decoration: none; + transition: all 0.15s ease; + + &:hover { + background: white; + color: #2196F3; + border-color: #2196F3; + } + + .material-icons { + font-size: 14px; + } + } + } + } + + .post-preview { + padding: 1.25rem; + + .post-author { + display: flex; + align-items: start; + gap: 0.75rem; + margin-bottom: 1rem; + + .author-avatar { + width: 40px; + height: 40px; + border-radius: 50%; + border: 2px solid #e5e7eb; + flex-shrink: 0; + } + + .author-info { + .author-name { + font-weight: 600; + color: #111827; + margin-bottom: 0.125rem; + + a { + color: inherit; + text-decoration: none; + + &:hover { + color: #2196F3; + } + } + } + + .post-location { + font-size: 0.8125rem; + color: #6b7280; + + a { + color: #2196F3; + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + + em { + color: #9ca3af; + font-style: normal; + } + } + } + } + + .post-content-preview { + .content-changed-notice { + display: flex; + align-items: center; + gap: 0.375rem; + padding: 0.5rem 0.75rem; + background: #fef3c7; + border: 1px solid #fbbf24; + border-radius: 6px; + margin-bottom: 1rem; + font-size: 0.8125rem; + color: #92400e; + + .material-icons { + font-size: 16px; + color: #f59e0b; + } + } + + .content-text { + color: #374151; + line-height: 1.6; + font-size: 0.9375rem; + } + } + + .post-actions { + margin-top: 1rem; + padding-top: 1rem; + border-top: 1px solid #f3f4f6; + } + } + } + } +} + +// Moderation Activity Page +.activity-header { + background: white; + border-radius: 8px; + border: 1px solid #e5e7eb; + padding: 1.5rem; + margin-bottom: 1.5rem; + + .activity-title { + display: flex; + align-items: center; + + .material-icons { + font-size: 28px; + color: #6b7280; + margin-right: 0.75rem; + } + + h2 { + margin: 0; + font-size: 1.5rem; + font-weight: 600; + color: #111827; + } + } +} + +// Activity Feed +.activity-feed { + background: white; + border-radius: 8px; + border: 1px solid #e5e7eb; + overflow: hidden; + + .feed-header { + padding: 1.25rem 1.5rem; + background: #f9fafb; + border-bottom: 1px solid #e5e7eb; + + h3 { + margin: 0; + font-size: 1.125rem; + font-weight: 600; + color: #111827; + display: flex; + align-items: center; + + .material-icons { + margin-right: 0.5rem; + color: #6b7280; + font-size: 20px; + } + } + } + + .feed-items { + .feed-item { + display: flex; + gap: 1rem; + padding: 1.25rem 1.5rem; + border-bottom: 1px solid #f3f4f6; + transition: background 0.15s ease; + position: relative; + + &:hover { + background: #fafbfc; + } + + &:last-child { + border-bottom: none; + } + + .feed-item-indicator { + flex-shrink: 0; + + .material-icons { + width: 36px; + height: 36px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + + &.new-topic { + background: #dbeafe; + color: #2563eb; + } + + &.reply { + background: #f3f4f6; + color: #6b7280; + } + } + } + + .feed-item-content { + flex: 1; + min-width: 0; + + .feed-meta { + display: flex; + align-items: center; + gap: 0.5rem; + margin-bottom: 0.5rem; + font-size: 0.875rem; + flex-wrap: wrap; + + .feed-avatar { + width: 24px; + height: 24px; + border-radius: 50%; + border: 1px solid #e5e7eb; + } + + .feed-user { + font-weight: 600; + color: #111827; + + a { + color: inherit; + text-decoration: none; + + &:hover { + color: #2196F3; + } + } + } + + .feed-action { + color: #6b7280; + } + + .feed-location { + color: #6b7280; + + .feed-topic-link { + color: #2196F3; + text-decoration: none; + font-weight: 500; + + &:hover { + text-decoration: underline; + } + } + } + + .feed-time { + color: #9ca3af; + margin-left: auto; + } + } + + .feed-preview { + color: #374151; + line-height: 1.5; + margin-bottom: 0.75rem; + } + + .feed-actions { + display: flex; + gap: 0.5rem; + + .feed-action-btn { + padding: 0.25rem 0.625rem; + border: 1px solid #e5e7eb; + background: white; + border-radius: 4px; + font-size: 0.75rem; + color: #6b7280; + cursor: pointer; + text-decoration: none; + transition: all 0.15s ease; + display: inline-flex; + align-items: center; + gap: 0.25rem; + + .material-icons { + font-size: 14px; + } + + &:hover { + background: #f9fafb; + color: #374151; + } + + &.moderate { + color: #2196F3; + border-color: #2196F3; + + &:hover { + background: #2196F3; + color: white; + } + } + } + } + } + + .feed-item-status { + position: absolute; + top: 1.25rem; + right: 1.5rem; + + .status-badge { + padding: 0.25rem 0.625rem; + border-radius: 12px; + font-size: 0.7rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + + &.pending { + background: #fef3c7; + color: #92400e; + } + + &.blocked { + background: #fee2e2; + color: #991b1b; + } + } + } + } + } +} + +// Dark mode support +.dark { + .thredded--moderation-navigation { + background: #1f2937; + border-bottom-color: #374151; + + .thredded--moderation-navigation--item a { + color: #9ca3af; + + &:hover { + color: #42a5f5; + } + + &.active { + color: #42a5f5; + border-bottom-color: #42a5f5; + } + } + + input[type="search"] { + background: #111827; + border-color: #374151; + color: #f3f4f6; + + &:focus { + border-color: #42a5f5; + box-shadow: 0 0 0 3px rgba(66, 165, 245, 0.1); + } + } + } + + .stat-card { + background: #1f2937; + border-color: #374151; + + .stat-value { + color: #f3f4f6; + } + } + + .moderation-posts { + background: #1f2937; + border-color: #374151; + + .moderation-posts-header { + background: #111827; + border-bottom-color: #374151; + + h3 { + color: #f3f4f6; + } + + .filter-buttons button { + background: #1f2937; + border-color: #374151; + color: #9ca3af; + + &:hover { + background: #374151; + } + + &.active { + background: #2196F3; + color: white; + } + } + } + + .moderation-post { + border-bottom-color: #374151; + + &:hover { + background: #111827; + } + + .post-header .user-info .username { + color: #f3f4f6; + } + + .post-content .content-preview { + color: #d1d5db; + + &::after { + background: linear-gradient(transparent, #1f2937); + } + } + } + } +} +// Users Management Page +.users-header { + background: white; + border-radius: 8px; + border: 1px solid #e5e7eb; + padding: 1.5rem; + margin-bottom: 1.5rem; + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 1rem; + + .users-title { + display: flex; + align-items: center; + + .material-icons { + font-size: 28px; + color: #6b7280; + margin-right: 0.75rem; + } + + h2 { + margin: 0; + font-size: 1.5rem; + font-weight: 600; + color: #111827; + } + } + + .users-search { + flex: 1; + max-width: 400px; + + .search-form { + width: 100%; + } + + .search-input-wrapper { + display: flex; + align-items: center; + background: #f9fafb; + border: 1px solid #e5e7eb; + border-radius: 8px; + padding: 0.5rem 0.75rem; + transition: all 0.2s ease; + + &:focus-within { + border-color: #2196F3; + background: white; + box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1); + } + + .material-icons { + color: #9ca3af; + margin-right: 0.5rem; + font-size: 20px; + } + + .search-input { + flex: 1; + background: transparent; + border: none; + outline: none; + font-size: 0.875rem; + color: #374151; + + &::placeholder { + color: #9ca3af; + } + } + + .search-button { + padding: 0.375rem 0.875rem; + background: #2196F3; + color: white; + border: none; + border-radius: 6px; + font-size: 0.875rem; + font-weight: 500; + cursor: pointer; + transition: background 0.2s ease; + + &:hover { + background: #1976D2; + } + } + } + } +} + +.search-results-notice { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.75rem 1rem; + background: #eff6ff; + border: 1px solid #bfdbfe; + border-radius: 6px; + margin-bottom: 1rem; + font-size: 0.875rem; + color: #1e40af; + + .material-icons { + font-size: 18px; + } +} + +.users-table-container { + background: white; + border-radius: 8px; + border: 1px solid #e5e7eb; + overflow: hidden; + + .table-caption { + padding: 0.75rem 1rem; + background: #f9fafb; + border-bottom: 1px solid #e5e7eb; + font-size: 0.875rem; + color: #6b7280; + text-align: left; + } + + .users-table { + width: 100%; + border-collapse: collapse; + + thead { + background: #f9fafb; + + tr { + border-bottom: 1px solid #e5e7eb; + } + + th { + padding: 0.875rem 1rem; + text-align: left; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + color: #6b7280; + letter-spacing: 0.025em; + + .material-icons { + font-size: 16px; + vertical-align: middle; + margin-right: 0.375rem; + opacity: 0.7; + } + + &.user-column { + width: 40%; + } + + &.status-column { + width: 25%; + } + + &.updated-column { + width: 20%; + } + + &.actions-column { + width: 15%; + text-align: right; + } + } + } + + tbody { + .user-row { + border-bottom: 1px solid #f3f4f6; + transition: background 0.15s ease; + + &:hover { + background: #fafbfc; + } + + &:last-child { + border-bottom: none; + } + } + + td { + padding: 1rem; + font-size: 0.875rem; + color: #374151; + + &.user-cell { + .user-info { + display: flex; + align-items: center; + gap: 0.75rem; + + .user-avatar { + width: 40px; + height: 40px; + border-radius: 50%; + border: 2px solid #e5e7eb; + } + + .user-avatar-placeholder { + width: 40px; + height: 40px; + border-radius: 50%; + background: #f3f4f6; + display: flex; + align-items: center; + justify-content: center; + + .material-icons { + color: #9ca3af; + font-size: 20px; + } + } + + .user-details { + .user-name { + display: block; + font-weight: 600; + color: #111827; + text-decoration: none; + margin-bottom: 0.125rem; + + &:hover { + color: #2196F3; + } + } + + .user-meta { + font-size: 0.75rem; + color: #9ca3af; + } + } + } + } + + &.status-cell { + .moderation-badge { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.375rem 0.75rem; + border-radius: 9999px; + font-size: 0.75rem; + font-weight: 500; + + .material-icons { + font-size: 14px; + } + + &.approved { + background: #d1fae5; + color: #065f46; + + .material-icons { + color: #10b981; + } + } + + &.blocked { + background: #fee2e2; + color: #991b1b; + + .material-icons { + color: #ef4444; + } + } + + &.pending_moderation { + background: #fef3c7; + color: #92400e; + + .material-icons { + color: #f59e0b; + } + } + } + } + + &.updated-cell { + color: #6b7280; + } + + &.actions-cell { + text-align: right; + + .action-button { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.375rem 0.75rem; + border: 1px solid #e5e7eb; + background: white; + border-radius: 6px; + font-size: 0.75rem; + color: #6b7280; + text-decoration: none; + transition: all 0.15s ease; + + .material-icons { + font-size: 16px; + } + + &:hover { + border-color: #2196F3; + color: #2196F3; + background: #eff6ff; + } + } + } + } + } + } +} + +.no-results { + background: white; + border-radius: 8px; + border: 1px solid #e5e7eb; + padding: 3rem 2rem; + text-align: center; + + .no-results-icon { + margin-bottom: 1rem; + + .material-icons { + font-size: 64px; + color: #d1d5db; + } + } + + h3 { + margin: 0 0 0.5rem; + font-size: 1.25rem; + font-weight: 600; + color: #374151; + } + + p { + margin: 0 0 1.5rem; + color: #6b7280; + } + + .clear-search-btn { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: #f3f4f6; + border: 1px solid #e5e7eb; + border-radius: 6px; + color: #374151; + text-decoration: none; + font-size: 0.875rem; + transition: all 0.15s ease; + + .material-icons { + font-size: 18px; + } + + &:hover { + background: #e5e7eb; + border-color: #d1d5db; + } + } +} diff --git a/app/assets/stylesheets/private-message-compose.scss b/app/assets/stylesheets/private-message-compose.scss new file mode 100644 index 00000000..58a0a2d4 --- /dev/null +++ b/app/assets/stylesheets/private-message-compose.scss @@ -0,0 +1,546 @@ +// Private Message Compose Styling +// Clean, professional email composition interface + +// Page background +#thredded--new-private-topic { + background: linear-gradient(180deg, #f9fafb 0%, #f3f4f6 100%); + min-height: calc(100vh - 200px); +} + +// Main compose container +.compose-container { + max-width: 800px; + margin: 2.5rem auto 1.5rem; + padding: 0 1.5rem; +} + +// Compose wrapper for card effect +.compose-wrapper { + background: white; + border-radius: 12px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 2px rgba(0, 0, 0, 0.1); + overflow: hidden; + margin-bottom: 2rem; +} + +// Compose header +.compose-header { + background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); + padding: 1.25rem 1.5rem; + border-bottom: none; + + h1 { + font-size: 1.5rem; + font-weight: 600; + color: white; + margin: 0; + display: flex; + align-items: center; + + .material-icons { + font-size: 1.625rem; + margin-right: 0.625rem; + color: white; + opacity: 0.9; + } + } + + .compose-subtitle { + margin-top: 0.25rem; + font-size: 0.875rem; + color: rgba(255, 255, 255, 0.85); + margin-left: 2.25rem; + } +} + +// Compose form +.thredded--new-private-topic-form { + background: white; + border: none; + border-radius: 0; + padding: 0.5rem 0 0; + + .thredded--form-list { + margin: 0; + padding: 0; + list-style: none; + + li, + > div { + padding: 1rem 1.5rem; + border-bottom: 1px solid #f3f4f6; + margin: 0; + + &:last-child { + border-bottom: none; + background: #f9fafb; + padding: 1rem 1.5rem; + margin-top: 0; + } + } + + // Field labels + label { + display: block; + font-size: 0.875rem; + font-weight: 600; + color: #1f2937; + margin-bottom: 0.375rem; + + &::after { + content: ':'; + margin-left: 0.125rem; + } + } + + // Title field + li.title { + input[type="text"] { + width: 100%; + padding: 0.625rem 0.875rem; + font-size: 1rem; + border: 1px solid #d1d5db; + border-radius: 6px; + transition: all 0.15s ease; + + &:focus { + outline: none; + border-color: #3b82f6; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); + } + + &::placeholder { + color: #9ca3af; + } + } + } + + // Recipients field + textarea[data-thredded-users-select] { + width: 100%; + min-height: 44px; + max-height: 120px; + padding: 0.625rem 1rem; + font-size: 0.9375rem; + border: 1px solid #d1d5db; + border-radius: 6px; + resize: vertical; + transition: all 0.15s ease; + font-family: inherit; + + &:focus { + outline: none; + border-color: #3b82f6; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); + min-height: 60px; + } + + &::placeholder { + color: #9ca3af; + } + } + + // Content field - target the textarea with ID + textarea#private_topic_content, + textarea#private_post_content, + textarea[name*="[content]"] { + width: 100%; + min-height: 180px; + padding: 1rem 1.125rem; + font-size: 1rem; + border: 1px solid #d1d5db; + border-radius: 8px; + resize: vertical; + transition: all 0.15s ease; + font-family: inherit; + line-height: 1.6; + background: #fafafa; + + &:focus { + outline: none; + border-color: #3b82f6; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); + min-height: 200px; + background: white; + } + + &::placeholder { + color: #9ca3af; + } + } + } +} + +// Recipients helper text +.recipients-helper { + margin-top: 0.375rem; + font-size: 0.75rem; + color: #6b7280; + + .material-icons { + font-size: 0.875rem; + vertical-align: middle; + margin-right: 0.25rem; + } +} + +// Selected users display +.selected-users { + margin-top: 0.75rem; + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + + .user-tag { + display: inline-flex; + align-items: center; + padding: 0.375rem 0.625rem; + background: #eff6ff; + border: 1px solid #3b82f6; + border-radius: 16px; + font-size: 0.8125rem; + color: #1e40af; + + .remove-user { + margin-left: 0.375rem; + cursor: pointer; + color: #3b82f6; + font-weight: bold; + + &:hover { + color: #1e40af; + } + } + } +} + +// Form actions +.compose-actions { + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; + + .left-actions { + display: flex; + gap: 0.5rem; + } + + .right-actions { + display: flex; + gap: 0.5rem; + } +} + +// Submit button +.thredded--form--submit { + display: inline-flex; + align-items: center; + padding: 0.75rem 1.75rem; + background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); + color: white; + border: none; + border-radius: 6px; + font-size: 0.9375rem; + font-weight: 600; + cursor: pointer; + transition: all 0.15s ease; + box-shadow: 0 2px 4px rgba(59, 130, 246, 0.2); + + &:hover:not(:disabled) { + background: #2563eb; + transform: translateY(-1px); + box-shadow: 0 4px 6px -1px rgba(59, 130, 246, 0.2); + } + + &:focus { + outline: none; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3); + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } + + .material-icons { + font-size: 1.125rem; + margin-right: 0.5rem; + } +} + +// Cancel/back button +.btn-cancel { + display: inline-flex; + align-items: center; + padding: 0.625rem 1.25rem; + background: white; + color: #6b7280; + border: 1px solid #e5e7eb; + border-radius: 6px; + font-size: 0.875rem; + font-weight: 500; + text-decoration: none; + cursor: pointer; + transition: all 0.15s ease; + + &:hover { + background: #f9fafb; + border-color: #d1d5db; + color: #374151; + } + + &:focus { + outline: none; + box-shadow: 0 0 0 3px rgba(107, 114, 128, 0.1); + } +} + +// Preview button +.btn-preview { + display: inline-flex; + align-items: center; + padding: 0.625rem 1.25rem; + background: white; + color: #6b7280; + border: 1px solid #e5e7eb; + border-radius: 6px; + font-size: 0.875rem; + font-weight: 500; + cursor: pointer; + transition: all 0.15s ease; + + .material-icons { + font-size: 1rem; + margin-right: 0.375rem; + } + + &:hover { + background: #f9fafb; + border-color: #d1d5db; + } + + &.active { + background: #eff6ff; + border-color: #3b82f6; + color: #2563eb; + } +} + +// Preview area +.thredded--preview-area { + margin-top: 1rem; + padding: 1rem; + background: #f9fafb; + border: 1px solid #e5e7eb; + border-radius: 6px; + min-height: 100px; + + .thredded--preview-area--title { + font-size: 0.75rem; + font-weight: 600; + color: #6b7280; + text-transform: uppercase; + letter-spacing: 0.025em; + margin-bottom: 0.75rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid #e5e7eb; + } + + .thredded--preview-area--post { + color: #374151; + line-height: 1.6; + + &:empty::before { + content: 'Message preview will appear here...'; + color: #9ca3af; + font-style: italic; + } + } +} + +// Field errors +.thredded--form-field-errors { + margin-top: 0.375rem; + + ul { + margin: 0; + padding: 0; + list-style: none; + } + + li { + padding: 0.375rem 0.625rem !important; + background: #fef2f2; + border: 1px solid #fecaca !important; + border-radius: 4px; + color: #dc2626; + font-size: 0.8125rem; + margin-top: 0.25rem; + } +} + +// Autocomplete dropdown +.textcomplete-dropdown { + background: white; + border: 1px solid #e5e7eb; + border-radius: 6px; + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + margin-top: 0.25rem; + max-height: 200px; + overflow-y: auto; + + li { + padding: 0.5rem 0.75rem !important; + border-bottom: 1px solid #f3f4f6 !important; + cursor: pointer; + transition: background 0.15s ease; + + &:hover, + &.active { + background: #f3f4f6; + } + + &:last-child { + border-bottom: none !important; + } + } +} + +// Dark mode support +.dark { + #thredded--new-private-topic { + background: linear-gradient(180deg, #111827 0%, #0f172a 100%); + } + + .compose-wrapper { + background: #1f2937; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.4); + } + + .compose-header { + background: linear-gradient(135deg, #1e40af 0%, #1e3a8a 100%); + border-color: #374151; + + h1 { + color: #f3f4f6; + + .material-icons { + color: #60a5fa; + } + } + + .compose-subtitle { + color: #9ca3af; + } + } + + .thredded--new-private-topic-form { + background: #1f2937; + border-color: #374151; + + .thredded--form-list { + li, + > div { + border-bottom-color: #374151; + + &:last-child { + background: #111827; + } + } + + label { + color: #d1d5db; + } + + input[type="text"], + textarea { + background: #111827; + border-color: #374151; + color: #f3f4f6; + + &:focus { + border-color: #3b82f6; + } + + &::placeholder { + color: #6b7280; + } + } + } + } + + .recipients-helper { + color: #9ca3af; + } + + .selected-users { + .user-tag { + background: #1e293b; + border-color: #3b82f6; + color: #60a5fa; + } + } + + .btn-cancel { + background: #1f2937; + border-color: #374151; + color: #9ca3af; + + &:hover { + background: #374151; + } + } + + .thredded--preview-area { + background: #111827; + border-color: #374151; + + .thredded--preview-area--title { + color: #9ca3af; + border-bottom-color: #374151; + } + + .thredded--preview-area--post { + color: #d1d5db; + + &:empty::before { + color: #6b7280; + } + } + } +} + +// Mobile responsiveness +@media (max-width: 768px) { + .compose-container { + margin: 1rem auto; + } + + .compose-header { + padding: 1rem; + + h1 { + font-size: 1.25rem; + } + } + + .thredded--new-private-topic-form { + .thredded--form-list li { + padding: 1rem; + } + } + + .compose-actions { + flex-direction: column; + + .left-actions, + .right-actions { + width: 100%; + + button { + flex: 1; + } + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/private-messages.scss b/app/assets/stylesheets/private-messages.scss new file mode 100644 index 00000000..ffc5593d --- /dev/null +++ b/app/assets/stylesheets/private-messages.scss @@ -0,0 +1,524 @@ +// Private Messages / Inbox Styling +// Modern, clean inbox design for private conversations + +// Main container +.thredded--private-topics { + max-width: 1200px; + margin: 0 auto; + padding: 2rem 1rem; +} + +// Page header +.private-messages-header { + margin-bottom: 2rem; + padding-bottom: 1.5rem; + border-bottom: 2px solid #e5e7eb; + + .header-content { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 1rem; + } + + h1 { + font-size: 1.875rem; + font-weight: 700; + color: #111827; + margin: 0; + display: flex; + align-items: center; + + .material-icons { + font-size: 2rem; + margin-right: 0.75rem; + color: #3b82f6; + } + } + + .header-actions { + display: flex; + gap: 0.5rem; + + .btn-compose { + display: inline-flex; + align-items: center; + padding: 0.625rem 1.25rem; + background: #3b82f6; + color: white; + border: none; + border-radius: 6px; + font-size: 0.875rem; + font-weight: 500; + text-decoration: none; + transition: all 0.15s ease; + + &:hover { + background: #2563eb; + transform: translateY(-1px); + box-shadow: 0 4px 6px -1px rgba(59, 130, 246, 0.2); + } + + .material-icons { + font-size: 1.125rem; + margin-right: 0.5rem; + } + } + } +} + +// Inbox stats +.inbox-stats { + display: flex; + gap: 2rem; + margin-top: 0.75rem; + font-size: 0.875rem; + color: #6b7280; + + .stat { + display: flex; + align-items: center; + gap: 0.5rem; + + .material-icons { + font-size: 1rem; + opacity: 0.7; + } + + strong { + color: #374151; + font-weight: 600; + } + } +} + +// Messages list container +.messages-list { + background: white; + border: 1px solid #e5e7eb; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04); +} + +// Individual message/conversation row +.thredded--topics--topic { + display: flex; + align-items: center; + padding: 1rem 1.25rem; + border-bottom: 1px solid #f3f4f6; + transition: all 0.15s ease; + position: relative; + + &:hover { + background: #f9fafb; + } + + &:last-child { + border-bottom: none; + } + + // Unread indicator + &.thredded--topic-unread { + background: #fefce8; + border-left: 3px solid #facc15; + + .thredded--topics--title { + font-weight: 600; + color: #111827; + } + + &::before { + content: ''; + position: absolute; + left: 0.75rem; + top: 50%; + transform: translateY(-50%); + width: 8px; + height: 8px; + background: #3b82f6; + border-radius: 50%; + } + } +} + +// Participants avatars +.message-participants { + flex-shrink: 0; + margin-right: 1rem; + display: flex; + align-items: center; + + .participant-avatar { + width: 36px; + height: 36px; + border-radius: 50%; + border: 2px solid white; + margin-right: -8px; + position: relative; + background: #f3f4f6; + display: flex; + align-items: center; + justify-content: center; + + &:first-child { + z-index: 3; + } + + &:nth-child(2) { + z-index: 2; + } + + &:nth-child(3) { + z-index: 1; + } + + img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 50%; + } + + // Initials for users without avatars + .initials { + font-size: 0.75rem; + font-weight: 600; + color: #6b7280; + text-transform: uppercase; + } + } + + // More participants indicator + .more-participants { + margin-left: 0.25rem; + font-size: 0.75rem; + color: #6b7280; + font-weight: 500; + } +} + +// Message content area +.message-content { + flex: 1; + min-width: 0; + + .thredded--topics--title { + margin: 0 0 0.25rem 0; + font-size: 0.9375rem; + line-height: 1.4; + + a { + color: #374151; + text-decoration: none; + + &:hover { + color: #3b82f6; + } + } + } + + // Message preview/excerpt + .message-preview { + font-size: 0.8125rem; + color: #6b7280; + line-height: 1.4; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 500px; + } +} + +// Posts count badge +.thredded--topics--posts-count { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 24px; + height: 24px; + padding: 0 6px; + background: #f3f4f6; + color: #6b7280; + border-radius: 12px; + font-size: 0.75rem; + font-weight: 600; + margin-right: 1rem; + flex-shrink: 0; + + .thredded--topic-unread & { + background: #3b82f6; + color: white; + } +} + +// Timestamp and metadata +.thredded--topics--updated-by { + display: flex; + flex-direction: column; + align-items: flex-end; + font-size: 0.75rem; + color: #9ca3af; + font-style: normal; + min-width: 100px; + + time { + font-weight: 500; + } + + .thredded--topics--participants { + margin-top: 0.25rem; + display: flex; + gap: 0.25rem; + + a { + color: #6b7280; + text-decoration: none; + + &:hover { + color: #3b82f6; + text-decoration: underline; + } + } + } +} + +// Empty state +.thredded--empty { + text-align: center; + padding: 4rem 2rem; + background: white; + border: 1px solid #e5e7eb; + border-radius: 8px; + + &::before { + content: ''; + display: block; + width: 80px; + height: 80px; + margin: 0 auto 1.5rem; + background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='1.5'%3E%3Cpath d='M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z'/%3E%3C/svg%3E") no-repeat center; + background-size: contain; + opacity: 0.5; + } + + .thredded--empty--title { + font-size: 1.125rem; + color: #374151; + margin-bottom: 0.75rem; + font-weight: 600; + } + + p { + color: #6b7280; + font-size: 0.875rem; + margin-bottom: 1.5rem; + } + + .thredded--button { + display: inline-flex; + align-items: center; + padding: 0.625rem 1.25rem; + background: #3b82f6; + color: white; + border: none; + border-radius: 6px; + font-size: 0.875rem; + font-weight: 500; + text-decoration: none; + transition: all 0.15s ease; + + &:hover { + background: #2563eb; + transform: translateY(-1px); + box-shadow: 0 4px 6px -1px rgba(59, 130, 246, 0.2); + } + + .material-icons { + font-size: 1.125rem; + margin-right: 0.5rem; + } + } +} + +// Mark all read button +.thredded--button-wide { + display: inline-flex; + align-items: center; + justify-content: center; + width: 100%; + margin-top: 1rem; + padding: 0.625rem 1.25rem; + background: white; + color: #6b7280; + border: 1px solid #e5e7eb; + border-radius: 6px; + font-size: 0.875rem; + font-weight: 500; + text-decoration: none; + transition: all 0.15s ease; + + &:hover { + background: #f9fafb; + border-color: #d1d5db; + color: #374151; + } +} + +// Pagination +.thredded--pagination-bottom { + margin-top: 2rem; + + .pagination { + display: flex; + justify-content: center; + gap: 0.5rem; + + a, span { + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + border-radius: 4px; + text-decoration: none; + transition: all 0.15s ease; + } + + a { + background: white; + border: 1px solid #e5e7eb; + color: #374151; + + &:hover { + background: #f9fafb; + border-color: #d1d5db; + } + } + + .current { + background: #3b82f6; + color: white; + border: 1px solid #3b82f6; + } + } +} + +// Dark mode support +.dark { + .private-messages-header { + border-bottom-color: #374151; + + h1 { + color: #f3f4f6; + + .material-icons { + color: #60a5fa; + } + } + } + + .inbox-stats { + color: #9ca3af; + + .stat strong { + color: #d1d5db; + } + } + + .messages-list { + background: #1f2937; + border-color: #374151; + } + + .thredded--topics--topic { + border-bottom-color: #374151; + + &:hover { + background: #111827; + } + + &.thredded--topic-unread { + background: #1e293b; + border-left-color: #facc15; + } + } + + .message-content { + .thredded--topics--title a { + color: #e5e7eb; + + &:hover { + color: #60a5fa; + } + } + + .message-preview { + color: #9ca3af; + } + } + + .thredded--topics--posts-count { + background: #374151; + color: #d1d5db; + + .thredded--topic-unread & { + background: #3b82f6; + color: white; + } + } + + .thredded--empty { + background: #1f2937; + border-color: #374151; + + .thredded--empty--title { + color: #e5e7eb; + } + + p { + color: #9ca3af; + } + } +} + +// Mobile responsiveness +@media (max-width: 768px) { + .private-messages-header { + .header-content { + flex-direction: column; + align-items: flex-start; + } + + h1 { + font-size: 1.5rem; + } + } + + .inbox-stats { + flex-wrap: wrap; + gap: 1rem; + } + + .thredded--topics--topic { + padding: 0.875rem 1rem; + } + + .message-participants { + margin-right: 0.75rem; + + .participant-avatar { + width: 32px; + height: 32px; + } + } + + .message-content { + .message-preview { + max-width: 100%; + } + } + + .thredded--topics--updated-by { + min-width: auto; + font-size: 0.6875rem; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/thredded-overrides.scss b/app/assets/stylesheets/thredded-overrides.scss index a8590a06..c8e242c5 100644 --- a/app/assets/stylesheets/thredded-overrides.scss +++ b/app/assets/stylesheets/thredded-overrides.scss @@ -1,39 +1,27 @@ -@import "thredded"; +// Thredded Forum Overrides +// This file contains styling overrides for the Thredded forum gem -.thredded--topic-header--follow-info--follow { - position: static !important; +// Hide the SVG definition container completely +// These SVG icons are defined by Thredded but we use Material Icons instead +.thredded--svg-definitions { + display: none !important; + visibility: hidden !important; + position: absolute !important; + width: 0 !important; + height: 0 !important; + overflow: hidden !important; } -.thredded--topic-header--follow-info--unfollow { - position: static !important; +// Fallback: If any SVGs somehow still display, keep them small +// This ensures no giant icons break the layout +svg { + max-width: 1.5rem; + max-height: 1.5rem; } -#thredded--container { - margin-left: 32px !important; -} - -.thredded--container { - margin: 0; - margin-left: 3em !important; -} - -@media only screen and (min-width: 601px) { - .thredded--nav { - nav, nav .nav-wrapper i, nav a.sidenav-trigger, nav a.sidenav-trigger i { - height: inherit !important; - line-height: inherit !important; - } - } -} - -.thredded--main-container { - max-width: 100%; -} - -.thredded--post--content { - font-size: 12pt; -} - -.thredded--post { - margin-bottom: 1em !important; +// Specific IDs for thredded icons (belt and suspenders approach) +#thredded-follow-icon, +#thredded-lock-icon, +#thredded-unfollow-icon { + display: none !important; } \ No newline at end of file diff --git a/app/assets/stylesheets/thredded-overrides.scss.bak b/app/assets/stylesheets/thredded-overrides.scss.bak new file mode 100644 index 00000000..498c1b99 --- /dev/null +++ b/app/assets/stylesheets/thredded-overrides.scss.bak @@ -0,0 +1,31 @@ +@import "thredded"; + +.thredded--topic-header--follow-info--follow { + position: static !important; +} + +.thredded--topic-header--follow-info--unfollow { + position: static !important; +} + +#thredded--container { + margin-left: 32px !important; +} + +.thredded--container { + margin: 0; + margin-left: 3em !important; +} + + +.thredded--main-container { + max-width: 100%; +} + +.thredded--post--content { + font-size: 12pt; +} + +.thredded--post { + margin-bottom: 1em !important; +} \ No newline at end of file diff --git a/app/assets/stylesheets/topic-show.scss b/app/assets/stylesheets/topic-show.scss new file mode 100644 index 00000000..4e4dd2dd --- /dev/null +++ b/app/assets/stylesheets/topic-show.scss @@ -0,0 +1,540 @@ +// Topic Show Page Styling +// Full-width header with narrower content column layout + +// Topic header section - full width background +.topic-header-section { + background: #2196F3; // notebook-blue flat color + color: white; + margin: -2rem -9999px 1.5rem -9999px; + padding: 1.25rem 9999px; + + .topic-header-container { + max-width: 1280px; + margin: 0 auto; + padding: 0 1.5rem; + } + + // Topic title + .topic-title { + font-size: 1.5rem; + font-weight: 600; + margin-bottom: 0.625rem; + line-height: 1.3; + + @media (max-width: 768px) { + font-size: 1.25rem; + } + + .material-icons { + font-size: 1.25rem; + margin-right: 0.375rem; + vertical-align: middle; + opacity: 0.9; + } + } + + // Metadata row + .topic-meta { + display: flex; + flex-wrap: wrap; + align-items: center; + font-size: 0.875rem; + opacity: 0.95; + margin-bottom: 0.75rem; + + .meta-item { + display: flex; + align-items: center; + + .material-icons { + font-size: 0.875rem; + margin-right: 0.25rem; + opacity: 0.8; + } + + a { + color: white; + text-decoration: underline; + text-underline-offset: 2px; + + &:hover { + text-decoration-thickness: 2px; + } + } + + &:not(:last-child)::after { + content: '|'; + margin: 0 0.75rem; + opacity: 0.5; + } + } + } + + // Categories + .topic-categories { + display: flex; + flex-wrap: wrap; + gap: 0.375rem; + margin-top: 0.5rem; + + .category-badge { + display: inline-flex; + align-items: center; + padding: 0.125rem 0.5rem; + background: rgba(255, 255, 255, 0.15); + border: 1px solid rgba(255, 255, 255, 0.25); + border-radius: 12px; + font-size: 0.75rem; + font-weight: 500; + color: white; + + &:hover { + background: rgba(255, 255, 255, 0.25); + } + } + } + + // Follow/action buttons + .topic-actions { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-top: 0.75rem; + + button, a { + display: inline-flex; + align-items: center; + padding: 0.375rem 0.75rem; + background: transparent; + color: white; + border: 1px solid rgba(255, 255, 255, 0.3); + border-radius: 4px; + font-size: 0.8125rem; + font-weight: 500; + cursor: pointer; + text-decoration: none; + transition: all 0.15s ease; + + &:hover { + background: rgba(255, 255, 255, 0.15); + border-color: rgba(255, 255, 255, 0.5); + } + + .material-icons { + font-size: 0.875rem; + margin-right: 0.25rem; + } + + &.following { + background: rgba(255, 255, 255, 0.15); + color: white; + border: 1px solid rgba(255, 255, 255, 0.4); + + &:hover { + background: rgba(255, 255, 255, 0.25); + } + } + + &.text-red-600 { + border-color: rgba(255, 255, 255, 0.3); + + &:hover { + background: rgba(220, 38, 38, 0.2); + border-color: rgba(220, 38, 38, 0.5); + } + } + } + } +} + +// Content area - narrower column +.topic-content-area { + max-width: 48rem; // 768px - narrower than the header + margin: 0 auto; + padding: 0 1.5rem; + + // Posts container + .posts-container { + margin-bottom: 2rem; + } +} + +// Individual post styling - Modern chat bubble design +.thredded--post { + margin-bottom: 1.5rem; + position: relative; + + // Override default thredded styles + background: transparent; + border: none; + box-shadow: none; + overflow: visible; + + // The speech bubble content styling + .prose { + font-size: 0.9375rem; + line-height: 1.65; + + p { + margin-bottom: 0.75rem; + + &:last-child { + margin-bottom: 0; + } + } + + blockquote { + margin: 0.75rem 0; + padding-left: 1rem; + border-left: 3px solid #2196F3; + color: #6b7280; + font-style: italic; + background: #f9fafb; + padding: 0.75rem 1rem; + border-radius: 0.25rem; + } + + code { + background: #f3f4f6; + padding: 0.125rem 0.375rem; + border-radius: 3px; + font-size: 0.875rem; + color: #d97706; + } + + pre { + background: #1f2937; + color: #f3f4f6; + padding: 1rem; + border-radius: 6px; + overflow-x: auto; + margin: 0.75rem 0; + + code { + background: transparent; + padding: 0; + color: inherit; + } + } + + a { + color: #2196F3; + text-decoration: none; + border-bottom: 1px solid transparent; + transition: border-color 0.15s ease; + + &:hover { + border-bottom-color: #2196F3; + } + } + + ul, ol { + margin: 0.75rem 0; + padding-left: 1.5rem; + } + + li { + margin: 0.25rem 0; + } + } + + // First unread post indicator + &.thredded--unread--post { + .post-content-card { + border-bottom: 3px solid #2196F3; + padding-bottom: calc(1rem - 3px); // Adjust padding to account for border + } + } +} + +// Post actions dropdown styling +.thredded--post--dropdown { + position: relative; + display: inline-block; + + .thredded--post--dropdown--toggle { + width: 20px; + height: 20px; + cursor: pointer; + opacity: 0.5; + transition: opacity 0.15s ease; + + &:hover { + opacity: 1; + } + } + + .thredded--post--dropdown--actions { + position: absolute; + right: 0; + top: 100%; + margin-top: 0.25rem; + background: white; + border: 1px solid #e5e7eb; + border-radius: 6px; + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); + min-width: 140px; + display: none; + z-index: 10; + + a { + display: block; + padding: 0.5rem 0.75rem; + font-size: 0.8125rem; + color: #6b7280; + text-decoration: none; + transition: all 0.15s ease; + + &:hover { + background: #f9fafb; + color: #2196F3; + } + + &:first-child { + border-radius: 6px 6px 0 0; + } + + &:last-child { + border-radius: 0 0 6px 6px; + } + } + } + + &:hover .thredded--post--dropdown--actions, + .thredded--post--dropdown--toggle:focus + .thredded--post--dropdown--actions { + display: block; + } +} + +// Reply form +.reply-form-section { + background: white; + border: 1px solid #e5e7eb; + border-radius: 8px; + overflow: hidden; + margin-top: 2rem; + + .reply-form-header { + padding: 1.25rem 1.5rem; + background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%); + border-bottom: 1px solid #e5e7eb; + + h3 { + font-size: 1.125rem; + font-weight: 600; + color: #111827; + margin: 0; + display: flex; + align-items: center; + + .material-icons { + font-size: 1.25rem; + margin-right: 0.5rem; + color: #2196F3; + } + } + } + + .reply-form-body { + padding: 1.5rem; + } +} + +// Pagination styling +.topic-pagination { + display: flex; + justify-content: center; + margin: 1.5rem 0; + + .pagination { + display: flex; + gap: 0.5rem; + + a, span { + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + border-radius: 4px; + text-decoration: none; + transition: all 0.15s ease; + } + + a { + background: white; + border: 1px solid #e5e7eb; + color: #374151; + + &:hover { + background: #f9fafb; + border-color: #d1d5db; + } + } + + .current { + background: #2196F3; + color: white; + border: 1px solid #2196F3; + } + + .disabled { + opacity: 0.5; + cursor: not-allowed; + } + } +} + +// Locked topic notice +.locked-notice { + background: #fef3c7; + border: 1px solid #fbbf24; + border-radius: 6px; + padding: 1rem; + margin: 1.5rem 0; + display: flex; + align-items: start; + gap: 0.75rem; + + .material-icons { + color: #f59e0b; + font-size: 1.25rem; + flex-shrink: 0; + } + + p { + margin: 0; + color: #92400e; + font-size: 0.875rem; + line-height: 1.4; + } +} + +// Dark mode support +.dark { + .topic-header-section { + background: linear-gradient(135deg, #1e40af 0%, #1e3a8a 100%); + + .category-badge { + background: rgba(30, 58, 138, 0.5); + border-color: rgba(59, 130, 246, 0.5); + } + + .topic-actions { + button, a { + background: #1f2937; + color: #42a5f5; + + &:hover { + background: #111827; + } + + &.following { + background: rgba(59, 130, 246, 0.2); + color: white; + border-color: rgba(59, 130, 246, 0.5); + } + } + } + } + + .thredded--post { + background: #1f2937; + border-color: #374151; + + .thredded--post--user { + background: #111827; + border-bottom-color: #374151; + + .thredded--post--user-link { + color: #f3f4f6; + + &:hover { + color: #42a5f5; + } + } + + .thredded--post--created-at { + color: #9ca3af; + } + } + + .thredded--post--content { + color: #d1d5db; + + blockquote { + border-left-color: #4b5563; + color: #9ca3af; + } + + code { + background: #374151; + color: #f3f4f6; + } + + pre { + background: #111827; + } + } + + .thredded--post--actions { + background: #111827; + border-top-color: #374151; + + a { + color: #9ca3af; + + &:hover { + color: #42a5f5; + } + } + } + } + + .reply-form-section { + background: #1f2937; + border-color: #374151; + + .reply-form-header { + background: linear-gradient(135deg, #111827 0%, #0f172a 100%); + border-bottom-color: #374151; + + h3 { + color: #f3f4f6; + } + } + } + + .locked-notice { + background: #451a03; + border-color: #92400e; + + .material-icons { + color: #fbbf24; + } + + p { + color: #fef3c7; + } + } +} + +// Mobile responsiveness +@media (max-width: 768px) { + .topic-header-section { + margin-left: -1.5rem; + margin-right: -1.5rem; + padding-left: 1.5rem; + padding-right: 1.5rem; + } + + .topic-content-area { + padding: 0 1rem; + } + + .thredded--post { + .thredded--post--user, + .thredded--post--content, + .thredded--post--actions { + padding-left: 1rem; + padding-right: 1rem; + } + } +} \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 490cfb23..7f59046a 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -129,4 +129,17 @@ module ApplicationHelper # Return the first sorted image, or nil if none available combined.first end + + def unread_inbox_count + return 0 unless user_signed_in? + + @unread_inbox_count ||= begin + Thredded::PrivateTopic + .for_user(current_user) + .unread(current_user) + .count + rescue + 0 + end + end end diff --git a/app/views/layouts/_sidenav.html.erb b/app/views/layouts/_sidenav.html.erb index 9338dd49..3ef73924 100644 --- a/app/views/layouts/_sidenav.html.erb +++ b/app/views/layouts/_sidenav.html.erb @@ -200,6 +200,15 @@ <%= current_user.on_premium_plan? ? 'Premium' : 'Starter' %> <% end %> +