new stream design

This commit is contained in:
Andrew Brown 2025-07-10 02:27:42 -07:00
parent 0a027681c7
commit df088d195a
9 changed files with 1017 additions and 481 deletions

View File

@ -0,0 +1,78 @@
# Stream Redesign Summary
## 🎨 Professional, Minimalist, and Fun Redesign Complete!
The social activity stream has been completely redesigned with a modern, professional aesthetic that maintains fun and engaging elements.
### ✅ Key Improvements Made
#### **Visual Design**
- **Glass morphism effects** - Frosted glass header with backdrop blur
- **Gradient backgrounds** - Subtle gradients from indigo to purple throughout
- **Professional color palette** - Indigo, purple, and pink accents with clean grays
- **Enhanced typography** - Better font weights, sizing, and spacing hierarchy
- **Rounded corners** - Modern 2xl border radius for cards and components
#### **Interactive Elements**
- **Smooth animations** - Hover effects, scale transforms, and smooth transitions
- **Gradient buttons** - Eye-catching CTAs with shadow effects and hover states
- **Interactive cards** - Subtle glow effects on hover, professional shadows
- **Status indicators** - Online status dots, content type badges
- **Micro-interactions** - Button hover states, form focus effects
#### **Layout & UX**
- **Sticky glass header** - Professional navigation that stays visible
- **Card-based design** - Clean, organized content in beautiful cards
- **Better spacing** - Generous whitespace and consistent padding
- **Visual hierarchy** - Clear content organization with dividers and sections
- **Mobile responsive** - Works beautifully across all device sizes
#### **Technical Fixes**
- **MaterializeCSS conflicts resolved** - No more double dropdowns
- **Form styling** - Tailwind-styled selects work properly
- **JavaScript protection** - Prevents MaterializeCSS initialization on Tailwind components
### 🚀 New Features
#### **Enhanced Share Creation**
- Beautiful gradient-bordered creation card
- Better placeholder text and instructions
- Visual feedback for public sharing
- Professional form styling
#### **Modern Feed Items**
- Glass morphism card design
- Content type badges with brand colors
- Interactive hover effects
- Better comment threading
- Professional interaction buttons (Like, Comment, Share)
#### **Improved Navigation**
- Icon-enhanced navigation buttons
- Search with keyboard shortcut indicators
- Professional toggle states
- Smooth transitions between views
#### **Professional Empty States**
- Beautiful empty state illustrations
- Encouraging call-to-action buttons
- Context-appropriate messaging
### 🎯 Design Principles Applied
1. **Professional** - Clean lines, consistent spacing, professional typography
2. **Minimalist** - Removed visual clutter, focused on content
3. **Fun** - Gradients, animations, playful hover effects
4. **Modern** - Glass morphism, subtle shadows, rounded corners
5. **Accessible** - Good contrast, clear hierarchy, readable fonts
### 💫 Visual Effects Used
- **Backdrop blur filters** for glass effects
- **CSS gradients** for backgrounds and buttons
- **Box shadows** with color tinting
- **Transform animations** for hover states
- **Opacity transitions** for smooth interactions
- **Border radius** for modern appearance
The stream now feels like a premium, professional social platform while maintaining the creative and fun nature that makes Notebook.ai special!

View File

@ -1,4 +1,5 @@
class ContentPageSharesController < ApplicationController
layout 'tailwind', only: [:show]
before_action :authenticate_user!, except: [:show]
before_action :set_content_page_share, only: [
:show, :edit, :update, :destroy,

View File

@ -1,11 +1,11 @@
class StreamController < ApplicationController
layout 'tailwind', only: [:index]
layout 'tailwind', only: [:index, :global]
before_action :authenticate_user!
before_action :set_stream_navbar_actions, only: [:index, :global]
before_action :set_stream_navbar_color, only: [:index, :global]
before_action :set_sidenav_expansion
before_action :cache_linkable_content_for_each_content_type, only: [:index]
before_action :cache_linkable_content_for_each_content_type, only: [:index, :global]
def index
@page_title = "What's happening"
@ -18,7 +18,17 @@ class StreamController < ApplicationController
.order('created_at DESC')
.includes([:content_page, :secondary_content_page])
.includes({ share_comments: [:user], user: [:avatar_attachment] })
.limit(25)
# Apply search filter if present
if params[:search].present?
search_term = "%#{params[:search]}%"
@feed = @feed.joins(:user).where(
"content_page_shares.message ILIKE ? OR users.name ILIKE ? OR users.email ILIKE ?",
search_term, search_term, search_term
)
end
@feed = @feed.limit(25)
end
def community
@ -35,7 +45,17 @@ class StreamController < ApplicationController
.order('created_at DESC')
.includes([:content_page, :secondary_content_page])
.includes({ share_comments: [:user], user: [:avatar_attachment] })
.limit(25)
# Apply search filter if present
if params[:search].present?
search_term = "%#{params[:search]}%"
@feed = @feed.joins(:user).where(
"content_page_shares.message ILIKE ? OR users.name ILIKE ? OR users.email ILIKE ?",
search_term, search_term, search_term
)
end
@feed = @feed.limit(25)
end
def set_stream_navbar_color

View File

@ -0,0 +1,117 @@
# Stream Events Integration
This document explains how to easily create stream events from anywhere in the application using the `StreamEventService`.
## Usage Examples
### 1. Manual Page Sharing
```ruby
# When a user manually shares a page
StreamEventService.create_share_event(
user: current_user,
content_page: @character,
message: "Check out my new character!"
)
```
### 2. Collection Publishing
```ruby
# When a page gets published to a collection
StreamEventService.create_collection_published_event(
user: @page.user,
content_page: @page,
collection: @collection
)
```
### 3. Document Publishing
```ruby
# When a user publishes a document
StreamEventService.create_document_published_event(
user: current_user,
document: @document
)
```
### 4. Generic Activity Events
```ruby
# Generic method for various activity types
StreamEventService.create_activity_event(
user: current_user,
activity_type: :published_to_collection,
target: {
content_page: @page,
collection: @collection
}
)
```
## Integration Points
### In Controllers
Add stream events to existing controllers:
```ruby
# In page_collections_controller.rb
def add_page_to_collection
# ... existing logic ...
if @submission.approved?
StreamEventService.create_collection_published_event(
user: @submission.content_page.user,
content_page: @submission.content_page,
collection: @collection
)
end
end
```
### In Jobs/Background Tasks
```ruby
class PublishToCollectionJob < ApplicationJob
def perform(page_id, collection_id)
# ... existing logic ...
StreamEventService.create_activity_event(
user: page.user,
activity_type: :published_to_collection,
target: { content_page: page, collection: collection }
)
end
end
```
### In Models (after_save callbacks)
```ruby
class Document < ApplicationRecord
after_update :create_stream_event_if_published
private
def create_stream_event_if_published
if saved_change_to_privacy? && privacy == 'public'
StreamEventService.create_document_published_event(
user: self.user,
document: self
)
end
end
end
```
## Extending the System
To add new event types:
1. Add a new method to `StreamEventService`
2. Add a case to `create_activity_event` method
3. Optionally create new partial templates in `app/views/stream/` for custom event rendering
The system is designed to be lightweight and extensible while maintaining consistency with the existing notification system.

View File

@ -0,0 +1,66 @@
class StreamEventService
def self.create_share_event(user:, content_page:, message: nil)
return unless user && content_page
# Make the content page public when sharing
content_page.update(privacy: 'public') if content_page.respond_to?(:privacy)
ContentPageShare.create!(
user: user,
content_page: content_page,
message: message,
shared_at: DateTime.current
)
end
def self.create_collection_published_event(user:, content_page:, collection:)
return unless user && content_page && collection
message = "#{content_page.name} was featured in the collection #{collection.name}!"
create_share_event(
user: user,
content_page: content_page,
message: message
)
end
def self.create_forum_thread_event(user:, thread_title:, thread_url:)
# For forum threads, we'll need to create a different type of stream event
# This would require extending the ContentPageShare model or creating a new model
# For now, this is a placeholder for future implementation
Rails.logger.info "StreamEventService: Would create forum thread event for #{user.display_name}: #{thread_title}"
end
def self.create_document_published_event(user:, document:)
return unless user && document
create_share_event(
user: user,
content_page: document,
message: "Just published this document!"
)
end
# Helper method to create notification-style stream events
def self.create_activity_event(user:, activity_type:, target:, message: nil)
case activity_type
when :published_to_collection
create_collection_published_event(
user: user,
content_page: target[:content_page],
collection: target[:collection]
)
when :shared_document
create_document_published_event(user: user, document: target)
when :forum_thread
create_forum_thread_event(
user: user,
thread_title: target[:title],
thread_url: target[:url]
)
else
Rails.logger.warn "StreamEventService: Unknown activity type: #{activity_type}"
end
end
end

View File

@ -1,150 +1,198 @@
<div class="stream-item row">
<div class="col s12 m12 l4">
<div class="grey-text uppercase">
<br />
Shared page
</div>
<% if @share.content_page %>
<div class="hoverable card">
<div class="card-image">
<%= link_to @share.content_page do %>
<%= image_tag @share.content_page.first_public_image %>
<span class="card-title bordered-text">
<i class="material-icons <%= @share.content_page.class.text_color %> left small"><%= @share.content_page.class.icon %></i>
<%= @share.content_page.name %>
</span>
<% end %>
</div>
</div>
<% else %>
<div class="hoverable card">
The shared page has been removed.
</div>
<% end %>
<div class="grey-text uppercase">
<br />
Created by
</div>
<%= link_to @share.user do %>
<div class="hoverable card <%= User.color %>">
<!-- todo vertical card stack user avatar -->
<div class="card-content">
<div class="card-title white-text">
<i class="material-icons left"><%= User.icon %></i>
<%= @share.user.display_name %>
<div class="min-h-screen bg-gray-100 py-8">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="lg:grid lg:grid-cols-12 lg:gap-8">
<!-- Sidebar -->
<aside class="lg:col-span-4">
<!-- Shared Content Card -->
<div class="bg-white rounded-lg shadow-sm border border-gray-200 mb-6">
<div class="p-4 border-b border-gray-200">
<h3 class="text-sm font-medium text-gray-500 uppercase tracking-wide">Shared Page</h3>
</div>
<%= render partial: 'thredded/users/badge', locals: { user: @share.user } %>
</div>
</div>
<% end %>
<br />
<div>
<ul>
<li class="uppercase grey-text">
Share Actions
</li>
<li>
<% if @share.followed_by?(current_user) %>
<%= link_to 'Unfollow this share', unfollow_user_content_page_share_path(user_id: @share.user.id, id: @share.id) %>
<% if @share.content_page %>
<div class="relative">
<%= link_to @share.content_page, class: "block hover:shadow-lg transition-shadow" do %>
<% if @share.content_page.respond_to?(:first_public_image) && @share.content_page.first_public_image.present? %>
<div class="aspect-w-16 aspect-h-9">
<%= image_tag @share.content_page.first_public_image, class: "w-full h-48 object-cover rounded-t-lg" %>
</div>
<% end %>
<div class="p-4" style="border-left: 4px solid <%= @share.content_page.class.hex_color %>">
<div class="flex items-center">
<i class="material-icons text-sm mr-2" style="color: <%= @share.content_page.class.hex_color %>"><%= @share.content_page.class.icon %></i>
<h4 class="text-lg font-semibold text-gray-900"><%= @share.content_page.name %></h4>
</div>
</div>
<% end %>
</div>
<% else %>
<%= link_to 'Follow this share', follow_user_content_page_share_path(user_id: @share.user.id, id: @share.id) %>
<% end %>
</li>
<% if @share.user == current_user %>
<li>
<%=
link_to user_content_page_share_path(user_id: @share.user.id, id: @share.id),
method: :DELETE,
data: { confirm: "Are you sure? This will delete this share and any comments that have been posted to it!" } do
%>
Delete this share
<% end %>
</li>
<% else %>
<li>
<%= link_to report_user_content_page_share_path(user_id: @share.user.id, id: @share.id) do %>
Report this share
<% end %>
</li>
<% end %>
<li>
<%= link_to 'Back to your stream', main_app.stream_path %>
</li>
</ul>
</div>
<div>
<ul>
<li class="grey-text uppercase">
Reshare to...
</li>
<li>
<%= link_to [
'http://twitter.com/share?',
'url=' + CGI.escape(user_content_page_share_url(user_id: @share.user.id, id: @share.id)),
'&text=' + CGI.escape(@share.message)
].join, class: 'blue-text', target: '_blank' do %>
<i class="material-icons tiny left" style="margin-top: 4px;">share</i>
Twitter
<% end %>
</li>
<li>
<%=
link_to "https://www.facebook.com/sharer/sharer.php?app_id=1523926344336934&u=#{CGI.escape(user_content_page_share_url(user_id: @share.user.id, id: @share.id))}&display=popup&ref=plugin&src=share_button",
class: 'blue-text',
onclick: "return !window.open(this.href, 'Facebook', 'width=640,height=580')" do
%>
<i class="material-icons tiny left" style="margin-top: 4px">share</i>
Facebook
<% end %>
</li>
</ul>
</div>
</div>
<div class="col s12 m12 l7">
<div class="card">
<div class="card-content">
<p>
<%= link_to @share.user, class: "#{User.text_color}" do %>
<%= image_tag @share.user.image_url(size=20), class: 'left circle avatar' %>
<%= @share.user.name %>
<% end %>
said:
<span class="grey-text right">
<%= time_ago_in_words @share.shared_at %> ago
</span>
</p>
<% if @share.message.present? %>
<blockquote class="original-comment black-text">
<%=
simple_format ContentFormatterService.show(
text: @share.message,
viewing_user: current_user
)
%>
</blockquote>
<% end %>
<%= render partial: 'share_comments/form', locals: { share: @share } %>
<br /><br />
<div class="uppercase grey-text center">
<%= pluralize @share.share_comments.count, 'comment' %>
</div>
<div class="row">
<% @share.share_comments.each do |comment| %>
<%=
render partial: 'share_comments/show',
locals: { comment: comment, share: @share }
%>
<div class="p-4 text-center text-gray-500">
<i class="material-icons text-4xl text-gray-300 mb-2">help_outline</i>
<p>The shared page has been removed.</p>
</div>
<% end %>
</div>
<% if @share.share_comments.count > 10 %>
<%= render partial: 'share_comments/form', locals: { share: @share } %>
<% end %>
<br /><br />
</div>
<!-- User Card -->
<div class="bg-white rounded-lg shadow-sm border border-gray-200 mb-6">
<div class="p-4 border-b border-gray-200">
<h3 class="text-sm font-medium text-gray-500 uppercase tracking-wide">Shared By</h3>
</div>
<%= link_to @share.user, class: "block p-4 hover:bg-gray-50 transition-colors" do %>
<div class="flex items-center">
<%= image_tag @share.user.image_url(size: 48), class: "h-12 w-12 rounded-full mr-4" %>
<div>
<h4 class="text-lg font-semibold text-gray-900"><%= @share.user.display_name %></h4>
<%= render partial: 'thredded/users/badge', locals: { user: @share.user } %>
</div>
</div>
<% end %>
</div>
<!-- Actions -->
<div class="bg-white rounded-lg shadow-sm border border-gray-200 mb-6">
<div class="p-4 border-b border-gray-200">
<h3 class="text-sm font-medium text-gray-500 uppercase tracking-wide">Actions</h3>
</div>
<div class="p-4 space-y-2">
<% if @share.followed_by?(current_user) %>
<%= link_to unfollow_user_content_page_share_path(user_id: @share.user.id, id: @share.id),
class: "block w-full text-left px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-md" do %>
<i class="material-icons text-sm mr-2">notifications_off</i>
Unfollow this share
<% end %>
<% else %>
<%= link_to follow_user_content_page_share_path(user_id: @share.user.id, id: @share.id),
class: "block w-full text-left px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-md" do %>
<i class="material-icons text-sm mr-2">notifications</i>
Follow this share
<% end %>
<% end %>
<% if @share.user == current_user %>
<%= link_to user_content_page_share_path(user_id: @share.user.id, id: @share.id),
method: :DELETE,
data: { confirm: "Are you sure? This will delete this share and any comments that have been posted to it!" },
class: "block w-full text-left px-3 py-2 text-sm text-red-600 hover:bg-red-50 rounded-md" do %>
<i class="material-icons text-sm mr-2">delete</i>
Delete this share
<% end %>
<% else %>
<%= link_to report_user_content_page_share_path(user_id: @share.user.id, id: @share.id),
class: "block w-full text-left px-3 py-2 text-sm text-red-600 hover:bg-red-50 rounded-md" do %>
<i class="material-icons text-sm mr-2">report</i>
Report this share
<% end %>
<% end %>
<%= link_to main_app.stream_path,
class: "block w-full text-left px-3 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-md" do %>
<i class="material-icons text-sm mr-2">arrow_back</i>
Back to stream
<% end %>
</div>
</div>
<!-- Share to Social -->
<div class="bg-white rounded-lg shadow-sm border border-gray-200">
<div class="p-4 border-b border-gray-200">
<h3 class="text-sm font-medium text-gray-500 uppercase tracking-wide">Share</h3>
</div>
<div class="p-4 space-y-2">
<%= link_to [
'http://twitter.com/share?',
'url=' + CGI.escape(user_content_page_share_url(user_id: @share.user.id, id: @share.id)),
'&text=' + CGI.escape(@share.message.to_s)
].join, target: '_blank',
class: "flex items-center px-3 py-2 text-sm text-blue-600 hover:bg-blue-50 rounded-md" do %>
<i class="material-icons text-sm mr-2">share</i>
Twitter
<% end %>
<%= link_to "https://www.facebook.com/sharer/sharer.php?app_id=1523926344336934&u=#{CGI.escape(user_content_page_share_url(user_id: @share.user.id, id: @share.id))}&display=popup&ref=plugin&src=share_button",
onclick: "return !window.open(this.href, 'Facebook', 'width=640,height=580')",
class: "flex items-center px-3 py-2 text-sm text-blue-600 hover:bg-blue-50 rounded-md" do %>
<i class="material-icons text-sm mr-2">share</i>
Facebook
<% end %>
</div>
</div>
</aside>
<!-- Main Content -->
<main class="lg:col-span-8">
<div class="bg-white rounded-lg shadow-sm border border-gray-200">
<div class="p-6 border-b border-gray-200">
<div class="flex items-start space-x-3">
<%= image_tag @share.user.image_url(size: 40), class: "h-10 w-10 rounded-full" %>
<div class="flex-1">
<div class="flex items-center space-x-2">
<%= link_to @share.user, class: "font-medium text-gray-900 hover:text-gray-700" do %>
<%= @share.user.display_name %>
<% end %>
<span class="text-gray-500">shared this</span>
<span class="text-gray-400">•</span>
<span class="text-sm text-gray-500"><%= time_ago_in_words @share.shared_at %> ago</span>
</div>
<% if @share.message.present? %>
<div class="mt-3 text-gray-700">
<%= simple_format ContentFormatterService.show(text: @share.message, viewing_user: current_user) %>
</div>
<% end %>
</div>
</div>
</div>
<!-- Comments Section -->
<div class="p-6">
<!-- Comment Form -->
<div class="mb-6">
<%= form_for ShareComment.new, local: true, class: "flex space-x-3" do |f| %>
<%= f.hidden_field :content_page_share_id, value: @share.id %>
<div class="flex-shrink-0">
<%= image_tag current_user.image_url(size: 40), class: "h-10 w-10 rounded-full" %>
</div>
<div class="flex-1 space-y-3">
<%= f.text_area :message,
placeholder: "Add a comment...",
rows: 3,
class: "block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" %>
<div class="flex justify-end">
<%= f.submit "Post Comment", class: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %>
</div>
</div>
<% end %>
</div>
<!-- Comments List -->
<div class="border-t border-gray-200 pt-6">
<h3 class="text-lg font-medium text-gray-900 mb-4">
<%= pluralize @share.share_comments.count, 'comment' %>
</h3>
<% if @share.share_comments.any? %>
<div class="space-y-6">
<% @share.share_comments.each do |comment| %>
<div class="flex space-x-3">
<%= image_tag comment.user.image_url(size: 32), class: "h-8 w-8 rounded-full flex-shrink-0" %>
<div class="flex-1">
<div class="flex items-center space-x-2">
<span class="font-medium text-gray-900"><%= comment.user.display_name %></span>
<span class="text-sm text-gray-500"><%= time_ago_in_words comment.created_at %> ago</span>
</div>
<div class="mt-1 text-gray-700">
<%= simple_format ContentFormatterService.show(text: comment.message, viewing_user: current_user) %>
</div>
</div>
</div>
<% end %>
</div>
<% else %>
<p class="text-gray-500 text-center py-8">No comments yet. Be the first to comment!</p>
<% end %>
</div>
</div>
</div>
</main>
</div>
</div>
</div>

View File

@ -0,0 +1,172 @@
<div class="group relative">
<!-- Main card with clean material design -->
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6 hover:shadow-md transition-shadow duration-200">
<!-- Header -->
<div class="flex items-start justify-between mb-4">
<div class="flex items-center space-x-4">
<div class="relative">
<%= image_tag share.user.image_url(size: 48), class: "h-12 w-12 rounded-full shadow-sm" %>
<% if share.content_page %>
<div class="absolute -bottom-1 -right-1 h-6 w-6 rounded-full shadow-sm flex items-center justify-center" style="background-color: <%= share.content_page.class.hex_color %>;">
<i class="material-icons text-white text-sm"><%= share.content_page.class.icon %></i>
</div>
<% end %>
</div>
<div class="flex-1">
<div class="flex items-center space-x-2">
<%= link_to share.user, class: "font-semibold text-gray-900 hover:text-indigo-600 transition-colors" do %>
<%= share.user.display_name %>
<% end %>
<% if share.content_page %>
<span class="text-gray-500">shared a</span>
<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium" style="background-color: <%= share.content_page.class.hex_color %>20; color: <%= share.content_page.class.hex_color %>;">
<%= share.content_page.class.name.downcase %>
</span>
<% else %>
<span class="text-red-500">shared a deleted page</span>
<% end %>
</div>
<p class="text-sm text-gray-500 mt-0.5">
<%= time_ago_in_words share.created_at %> ago
</p>
</div>
</div>
<!-- Action menu -->
<div class="opacity-0 group-hover:opacity-100 transition-opacity">
<button class="p-1.5 text-gray-400 hover:text-gray-600 rounded-lg hover:bg-gray-50 transition-colors">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z"/>
</svg>
</button>
</div>
</div>
<!-- Message -->
<% if share.message.present? %>
<div class="mb-4">
<div class="prose prose-sm max-w-none text-gray-700 leading-relaxed">
<%= simple_format ContentFormatterService.show(text: share.message, viewing_user: current_user) %>
</div>
</div>
<% end %>
<!-- Content Preview -->
<% if share.content_page %>
<%= link_to [share.user, share], class: 'block group/content' do %>
<div class="relative overflow-hidden rounded-lg border border-gray-200 bg-gray-50 hover:shadow-sm hover:border-gray-300 transition-all duration-200">
<div class="flex">
<% if share.content_page.respond_to?(:first_public_image) && share.content_page.first_public_image.present? %>
<div class="flex-shrink-0 w-32 h-24">
<%= image_tag share.content_page.first_public_image, class: 'w-full h-full object-cover' %>
</div>
<% end %>
<div class="flex-1 p-4" style="border-left: 3px solid <%= share.content_page.class.hex_color %>;">
<h3 class="font-semibold text-gray-900 group-hover/content:text-indigo-600 transition-colors flex items-center">
<i class="material-icons text-lg mr-2" style="color: <%= share.content_page.class.hex_color %>"><%= share.content_page.class.icon %></i>
<%= share.content_page.name %>
</h3>
<% if share.content_page.respond_to?(:description) && share.content_page.description.present? %>
<p class="text-sm text-gray-600 mt-2 line-clamp-2">
<%= truncate(strip_tags(share.content_page.description), length: 120) %>
</p>
<% end %>
</div>
</div>
</div>
<% end %>
<% end %>
<!-- Interaction Bar -->
<div class="flex items-center justify-between mt-4 pt-4 border-t border-gray-200/50">
<div class="flex items-center space-x-6">
<!-- Comments -->
<button class="flex items-center space-x-2 text-gray-500 hover:text-indigo-600 transition-colors group/btn">
<div class="p-1.5 rounded-lg group-hover/btn:bg-indigo-50 transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"/>
</svg>
</div>
<span class="text-sm font-medium">
<% if share.share_comments.any? %>
<%= pluralize share.share_comments.count, 'comment' %>
<% else %>
Comment
<% end %>
</span>
</button>
<!-- Like (placeholder) -->
<button class="flex items-center space-x-2 text-gray-500 hover:text-red-600 transition-colors group/btn">
<div class="p-1.5 rounded-lg group-hover/btn:bg-red-50 transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
</svg>
</div>
<span class="text-sm font-medium">Like</span>
</button>
<!-- Share (placeholder) -->
<button class="flex items-center space-x-2 text-gray-500 hover:text-blue-600 transition-colors group/btn">
<div class="p-1.5 rounded-lg group-hover/btn:bg-blue-50 transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.367 2.684 3 3 0 00-5.367-2.684z"/>
</svg>
</div>
<span class="text-sm font-medium">Share</span>
</button>
</div>
</div>
<!-- Comments Section (if any) -->
<% if share.share_comments.any? %>
<div class="mt-4 pt-4 border-t border-gray-200/50">
<div class="space-y-4">
<% share.share_comments.limit(2).each do |comment| %>
<div class="flex space-x-3">
<%= image_tag comment.user.image_url(size: 32), class: "h-8 w-8 rounded-full flex-shrink-0" %>
<div class="flex-1 min-w-0">
<div class="bg-gray-50 rounded-lg px-3 py-2">
<div class="flex items-center space-x-2 mb-1">
<span class="font-medium text-sm text-gray-900"><%= comment.user.display_name %></span>
<span class="text-xs text-gray-500"><%= time_ago_in_words comment.created_at %> ago</span>
</div>
<div class="text-sm text-gray-700">
<%= simple_format ContentFormatterService.show(text: comment.message, viewing_user: current_user) %>
</div>
</div>
</div>
</div>
<% end %>
<% if share.share_comments.count > 2 %>
<div class="text-center">
<%= link_to [share.user, share], class: "text-sm text-indigo-600 hover:text-indigo-500 font-medium" do %>
View all <%= share.share_comments.count %> comments
<% end %>
</div>
<% end %>
</div>
</div>
<% end %>
<!-- Quick comment form -->
<div class="mt-4 pt-4 border-t border-gray-200/50">
<%= form_for ShareComment.new, local: true, class: "flex space-x-3" do |f| %>
<%= f.hidden_field :content_page_share_id, value: share.id %>
<div class="flex-shrink-0">
<%= image_tag current_user.image_url(size: 32), class: "h-8 w-8 rounded-full" %>
</div>
<div class="flex-1 flex space-x-3">
<%= f.text_area :message,
placeholder: "Add a thoughtful comment...",
rows: 1,
class: "flex-1 px-3 py-2 bg-gray-50 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 focus:bg-white transition-colors resize-none" %>
<%= f.submit "Post", class: "px-4 py-2 bg-blue-600 text-white text-sm font-medium rounded-lg shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors" %>
</div>
<% end %>
</div>
</div>
</div>

View File

@ -1,28 +1,196 @@
<br />
<div class="min-h-screen bg-gray-50" data-in-app="true">
<!-- Clean Header -->
<header class="sticky top-0 z-30 bg-white border-b border-gray-200 shadow-sm">
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-16">
<!-- Left: Navigation Toggle -->
<div class="flex items-center space-x-1">
<%= link_to stream_path, class: "inline-flex items-center px-4 py-2 text-sm font-medium rounded-md transition-colors #{'bg-blue-50 text-blue-700 border border-blue-200' if request.path == stream_path} #{'text-gray-600 hover:text-gray-900 hover:bg-gray-50' unless request.path == stream_path}" do %>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/>
</svg>
Following
<% end %>
<%= link_to stream_world_path, class: "inline-flex items-center px-4 py-2 text-sm font-medium rounded-md transition-colors #{'bg-blue-50 text-blue-700 border border-blue-200' if request.path == stream_world_path} #{'text-gray-600 hover:text-gray-900 hover:bg-gray-50' unless request.path == stream_world_path}" do %>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
Everyone
<% end %>
</div>
<div class="row">
<div class="col s12">
<%= render partial: 'content_page_shares/form' %>
<!-- Center: Search -->
<div class="flex-1 max-w-md mx-8">
<%= form_with url: request.path, method: :get, local: true do |f| %>
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="h-4 w-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
<%= f.text_field :search,
value: params[:search],
placeholder: "Search posts...",
class: "block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md text-sm placeholder-gray-500 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500" %>
</div>
<% end %>
</div>
<!-- Right: Empty for balance -->
<div class="w-24"></div>
</div>
</div>
</header>
<!-- Main Content Area -->
<div class="py-6 px-4 sm:px-6 lg:px-8">
<div class="max-w-2xl mx-auto">
<!-- Collapsible Share CTA -->
<div class="mb-6">
<div id="share-cta-collapsed" class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 cursor-pointer hover:shadow-md transition-shadow">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<%= image_tag current_user.image_url(size: 40), class: "h-10 w-10 rounded-full" %>
<div>
<p class="text-sm font-medium text-gray-900">Want to share a page with the world?</p>
<p class="text-xs text-gray-500">Share your work and get feedback from the community</p>
</div>
</div>
<svg class="h-5 w-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
</svg>
</div>
</div>
<div id="share-form-expanded" class="hidden bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
<%= form_for [current_user, ContentPageShare.new(user: current_user)], local: true, class: "tailwind-styled-form" do |f| %>
<div class="p-6 border-b border-gray-100">
<div class="flex items-start space-x-4">
<%= image_tag current_user.image_url(size: 48), class: "h-12 w-12 rounded-full" %>
<div class="flex-1">
<h3 class="text-lg font-medium text-gray-900 mb-1">Share a page</h3>
<p class="text-sm text-gray-600">Choose one of your pages to share with the community</p>
</div>
<button type="button" id="close-share-form" class="text-gray-400 hover:text-gray-600">
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
</div>
<div class="p-6 space-y-4">
<div>
<%= f.select :content_page,
options_for_select([['Select a page to share...', '']] +
@current_user_content.flat_map do |content_type, content_list|
content_list.sort_by(&:name).map { |content| ["#{content.name} (#{content_type})", "#{content_type}-#{content.id}"] }
end),
{},
{ class: "block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500" } %>
</div>
<div>
<%= f.text_area :message,
placeholder: "Add a message about your page (optional)",
rows: 3,
class: "block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-500 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 resize-none" %>
</div>
<div class="flex items-center justify-between pt-2">
<div class="flex items-center text-sm text-gray-500">
<svg class="w-4 h-4 mr-1.5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
Page will be made public
</div>
<%= f.submit "Share", class: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors" %>
</div>
</div>
<% end %>
</div>
</div>
<!-- Feed Header -->
<div class="flex items-center justify-between mb-6">
<div class="flex items-center space-x-3">
<div class="h-8 w-1 bg-blue-600 rounded-full"></div>
<h2 class="text-xl font-bold text-gray-900">
<%= request.path == stream_path ? "Following" : "Everyone" %>
</h2>
<span class="px-3 py-1 text-xs font-medium bg-gray-100 text-gray-600 rounded-full">
<%= @feed.length %> posts
</span>
</div>
</div>
<!-- Feed Content -->
<% if @feed.empty? %>
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-12 text-center">
<div class="mb-6">
<div class="mx-auto h-16 w-16 rounded-full bg-gray-100 flex items-center justify-center">
<svg class="h-8 w-8 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"/>
</svg>
</div>
</div>
<h3 class="text-xl font-semibold text-gray-900 mb-3">No posts here yet!</h3>
<p class="text-gray-600 mb-6 max-w-md mx-auto leading-relaxed">
<%= request.path == stream_path ?
"Follow other worldbuilders to see their amazing creations appear here." :
"Be the first to share something amazing with the community!" %>
</p>
<%= link_to "Discover Creators", users_path, class: "inline-flex items-center px-6 py-3 bg-blue-600 text-white font-semibold rounded-lg shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors" %>
</div>
<% else %>
<div class="space-y-6">
<% @feed.each_with_index do |share, index| %>
<%= render partial: 'stream/feed_item', locals: { share: share, is_last: index == @feed.length - 1 } %>
<% end %>
</div>
<!-- Load More -->
<div class="mt-12 text-center">
<button class="inline-flex items-center px-6 py-3 bg-white border border-gray-200 text-gray-700 font-medium rounded-lg shadow-sm hover:shadow-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all duration-200">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
</svg>
Load more posts
</button>
</div>
<% end %>
</div>
</div>
</div>
<%= render partial: 'stream/share', collection: @feed %>
<% if @feed.empty? %>
<div class="row">
<div class='col s12'>
<div class="hoverable card">
<div class="card-content">
<p class="card-title">
There are no posts here yet!
</p>
<p>
You can follow other worldbuilders from their profiles.
Whenever a user you follow shares one of their public pages,
it will appear here for you to comment on!
</p>
</div>
</div>
</div>
</div>
<% end %>
<script>
// Disable MaterializeCSS initialization for Tailwind-styled forms
document.addEventListener('DOMContentLoaded', function() {
// Prevent MaterializeCSS from initializing on Tailwind select elements
if (window.M && window.M.FormSelect) {
document.querySelectorAll('.tailwind-styled-form select').forEach(function(select) {
select.classList.add('no-autoinit');
});
}
// Handle collapsible share form
const shareCtaCollapsed = document.getElementById('share-cta-collapsed');
const shareFormExpanded = document.getElementById('share-form-expanded');
const closeShareForm = document.getElementById('close-share-form');
if (shareCtaCollapsed) {
shareCtaCollapsed.addEventListener('click', function() {
shareCtaCollapsed.classList.add('hidden');
shareFormExpanded.classList.remove('hidden');
});
}
if (closeShareForm) {
closeShareForm.addEventListener('click', function() {
shareFormExpanded.classList.add('hidden');
shareCtaCollapsed.classList.remove('hidden');
});
}
});
</script>

View File

@ -1,336 +1,202 @@
<div class="min-h-screen bg-gray-100">
<header class="bg-white shadow-sm lg:static lg:overflow-y-visible">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="relative flex justify-between xl:grid xl:grid-cols-12 lg:gap-8">
<div class="flex md:absolute md:left-0 md:inset-y-0 lg:static xl:col-span-2">
<div class="flex-shrink-0 flex items-center">
<span class="relative z-0 inline-flex shadow-sm rounded-md">
<button type="button" class="relative inline-flex items-center px-4 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-notebook-blue focus:border-notebook-blue">Following</button>
<button type="button" class="-ml-px relative inline-flex items-center px-4 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-notebook-blue focus:border-notebook-blue">Everyone</button>
</span>
</div>
<div class="min-h-screen bg-gray-50" data-in-app="true">
<!-- Clean Header -->
<header class="sticky top-0 z-30 bg-white border-b border-gray-200 shadow-sm">
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-16">
<!-- Left: Navigation -->
<div class="flex items-center space-x-1">
<%= link_to stream_path, class: "inline-flex items-center px-4 py-2 text-sm font-medium rounded-md transition-colors #{'bg-blue-50 text-blue-700 border border-blue-200' if request.path == stream_path} #{'text-gray-600 hover:text-gray-900 hover:bg-gray-50' unless request.path == stream_path}" do %>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/>
</svg>
Following
<% end %>
<%= link_to stream_world_path, class: "inline-flex items-center px-4 py-2 text-sm font-medium rounded-md transition-colors #{'bg-blue-50 text-blue-700 border border-blue-200' if request.path == stream_world_path} #{'text-gray-600 hover:text-gray-900 hover:bg-gray-50' unless request.path == stream_world_path}" do %>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
Everyone
<% end %>
</div>
<div class="min-w-0 flex-1 md:px-8 lg:px-0 xl:col-span-6">
<div class="flex items-center px-6 py-4 md:max-w-3xl md:mx-auto lg:max-w-none lg:mx-0 xl:px-0">
<div class="w-full">
<label for="search" class="sr-only">Share something...</label>
<div class="relative">
<div class="pointer-events-none absolute inset-y-0 left-0 pl-3 flex items-center">
<!-- Heroicon name: solid/search -->
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd" />
</svg>
</div>
<input id="search" name="search" class="block w-full bg-white border border-gray-300 rounded-md py-2 pl-10 pr-3 text-sm placeholder-gray-500 focus:outline-none focus:text-gray-900 focus:placeholder-gray-400 focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" placeholder="Search shared posts..." type="search">
<!-- Center: Search -->
<div class="flex-1 max-w-md mx-8">
<%= form_with url: request.path, method: :get, local: true do |f| %>
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="h-4 w-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
<%= f.text_field :search,
value: params[:search],
placeholder: "Search posts...",
class: "block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md text-sm placeholder-gray-500 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500" %>
</div>
</div>
</div>
<div class="flex md:absolute md:left-0 md:inset-y-0 lg:static xl:col-span-2">
<div class="flex-shrink-0 flex items-center">
rhs
</div>
<% end %>
</div>
<!-- Right: Empty for balance -->
<div class="w-24"></div>
</div>
</div>
</header>
<div class="py-6">
<div class="max-w-3xl mx-auto sm:px-6 lg:max-w-7xl lg:px-8 lg:grid lg:grid-cols-12 lg:gap-8">
<!--
<div class="hidden lg:block lg:col-span-3 xl:col-span-2">
<nav aria-label="Sidebar" class="divide-y divide-gray-300">
filters / highlights (each page, documents, timelines)
</nav>
<!-- Main Content Area -->
<div class="py-6 px-4 sm:px-6 lg:px-8">
<div class="max-w-2xl mx-auto">
<!-- Collapsible Share CTA -->
<div class="mb-6">
<div id="share-cta-collapsed" class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 cursor-pointer hover:shadow-md transition-shadow">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<%= image_tag current_user.image_url(size: 40), class: "h-10 w-10 rounded-full" %>
<div>
<p class="text-sm font-medium text-gray-900">Want to share a page with the world?</p>
<p class="text-xs text-gray-500">Share your work and get feedback from the community</p>
</div>
</div>
<svg class="h-5 w-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
</svg>
</div>
</div>
<div id="share-form-expanded" class="hidden bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
<%= form_for [current_user, ContentPageShare.new(user: current_user)], local: true, class: "tailwind-styled-form" do |f| %>
<div class="p-6 border-b border-gray-100">
<div class="flex items-start space-x-4">
<%= image_tag current_user.image_url(size: 48), class: "h-12 w-12 rounded-full" %>
<div class="flex-1">
<h3 class="text-lg font-medium text-gray-900 mb-1">Share a page</h3>
<p class="text-sm text-gray-600">Choose one of your pages to share with the community</p>
</div>
<button type="button" id="close-share-form" class="text-gray-400 hover:text-gray-600">
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
</div>
<div class="p-6 space-y-4">
<div>
<%= f.select :content_page,
options_for_select([['Select a page to share...', '']] +
@current_user_content.flat_map do |content_type, content_list|
content_list.sort_by(&:name).map { |content| ["#{content.name} (#{content_type})", "#{content_type}-#{content.id}"] }
end),
{},
{ class: "block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500" } %>
</div>
<div>
<%= f.text_area :message,
placeholder: "Add a message about your page (optional)",
rows: 3,
class: "block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-500 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 resize-none" %>
</div>
<div class="flex items-center justify-between pt-2">
<div class="flex items-center text-sm text-gray-500">
<svg class="w-4 h-4 mr-1.5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
Page will be made public
</div>
<%= f.submit "Share", class: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors" %>
</div>
</div>
<% end %>
</div>
</div>
-->
<main class="lg:col-span-12 xl:col-span-8">
<div class="bg-notebook-blue text-white my-8 p-2 rounded">
share input form TODO
<!-- Feed Header -->
<div class="flex items-center justify-between mb-6">
<div class="flex items-center space-x-3">
<div class="h-8 w-1 bg-blue-600 rounded-full"></div>
<h2 class="text-xl font-bold text-gray-900">
<%= request.path == stream_path ? "Following" : "Everyone" %>
</h2>
<span class="px-3 py-1 text-xs font-medium bg-gray-100 text-gray-600 rounded-full">
<%= @feed.length %> posts
</span>
</div>
<h2 class="text-gray-400 font-bold text-sm my-4">Shares from people you follow</h2>
<div class="flow-root">
<ul role="list" class="-mb-8">
<li>
<div class="relative pb-8">
<span class="absolute top-5 left-5 -ml-px h-full w-0.5 bg-gray-200" aria-hidden="true"></span>
<div class="relative flex items-start space-x-3">
<div class="relative">
<img class="h-10 w-10 rounded-full bg-gray-400 flex items-center justify-center ring-8 ring-white" src="https://images.unsplash.com/photo-1520785643438-5bf77931f493?ixlib=rb-=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=8&w=256&h=256&q=80" alt="">
<span class="absolute -bottom-2 -right-1.5 bg-white rounded-tl px-0.5">
<i class="material-icons <%= Creature.text_color %> text-base"><%= Creature.icon %></i>
</span>
</div>
<div class="min-w-0 flex-1">
<div>
<div class="text-sm text-gray-500">
<a href="#" class="font-medium text-gray-900">Andrew Brown</a>
<span class="mt-0.5">shared a <strong>Creature</strong></span>
<span class="px-1">&middot;</span>
<span class="">6h ago</span>
</div>
<p>
message with share
</p>
</div>
<div class="mt-2 text-sm text-gray-700">
<%= link_to '#', class: '' do %>
<div class="grid grid-cols-3 bg-white rounded hover:shadow-lg">
<div class="col-span-1">
<%= image_tag Character.last.random_image_including_private, class: 'w-full h-full rounded-l' %>
</div>
<div class="col-span-2 pl-4 pt-4 border-l-4 border-brown-500">
<h3 class="text-lg mb-4 font-bold">
<i class="material-icons <%= Creature.text_color %> float-left mr-2"><%= Creature.icon %></i>
Page name
</h3>
Details or description here
</div>
</div>
<% end %>
</div>
</div>
</div>
</div>
</li>
<li>
<div class="relative pb-8">
<span class="absolute top-5 left-5 -ml-px h-full w-0.5 bg-gray-200" aria-hidden="true"></span>
<div class="relative flex items-start space-x-3">
<div>
<div class="relative px-1">
<div class="relative">
<img class="h-10 w-10 rounded-full bg-gray-400 flex items-center justify-center ring-8 ring-white" src="https://images.unsplash.com/photo-1520785643438-5bf77931f493?ixlib=rb-=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=8&w=256&h=256&q=80" alt="">
<span class="absolute -bottom-2 -right-1.5 bg-white rounded-tl px-0.5">
<i class="material-icons <%= User.text_color %> text-base"><%= User.icon %></i>
</span>
</div>
</div>
</div>
<div class="min-w-0 flex-1 py-1.5">
<div class="text-sm text-gray-500">
<a href="#" class="font-medium text-gray-900">Dr. Evil</a>
followed
<a href="#" class="font-medium text-gray-900">Bob "Bob" Bobson</a>
<span class="px-1">&middot;</span>
<span class="text-sm text-gray-500">2d ago</span>
</div>
</div>
</div>
</div>
</li>
<li>
<div class="relative pb-8">
<span class="absolute top-5 left-5 -ml-px h-full w-0.5 bg-gray-200" aria-hidden="true"></span>
<div class="relative flex items-start space-x-3">
<div>
<div class="relative px-1">
<div class="relative">
<img class="h-10 w-10 rounded-full bg-gray-400 flex items-center justify-center ring-8 ring-white" src="https://images.unsplash.com/photo-1520785643438-5bf77931f493?ixlib=rb-=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=8&w=256&h=256&q=80" alt="">
<span class="absolute -bottom-2 -right-1.5 bg-white rounded-tl px-0.5">
<i class="material-icons text-blue-500 text-base">forum</i>
</span>
</div>
</div>
</div>
<div class="min-w-0 flex-1 py-0">
<div class="text-sm leading-8 text-gray-500">
<span class="mr-0.5">
<a href="#" class="font-medium text-gray-900">Dr. Evil</a>
started a forum discussion
</span>
<span class="px-1">&middot;</span>
<span class="text-sm text-gray-500">2d ago</span>
<div class="ml-1">
<a href="#" class="relative inline-flex items-center rounded-full border border-gray-300 px-3 py-1 text-sm bg-blue-500 hover:bg-blue-400 hover:shadow-lg">
<i class="material-icons float-left text-white">forum</i>
<span class="ml-3.5 font-medium text-white">What is the name of that guy who did the thing?</span>
</a>
</div>
</div>
</div>
</div>
</div>
</li>
<li>
<div class="relative pb-8">
<div class="relative flex items-start space-x-3">
<div class="relative">
<img class="h-10 w-10 rounded-full bg-gray-400 flex items-center justify-center ring-8 ring-white" src="https://images.unsplash.com/photo-1531427186611-ecfd6d936c79?ixlib=rb-=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=8&w=256&h=256&q=80" alt="">
<span class="absolute -bottom-2 -right-1.5 bg-white rounded-tl px-0.5">
<i class="material-icons <%= Document.text_color %> text-base"><%= Document.icon %></i>
</span>
</div>
<div class="min-w-0 flex-1">
<div class="text-sm">
<a href="#" class="font-medium text-gray-900">Jason Meyers</a>
<span class="text-gray-500">shared a <strong>Document</strong></span>
<span class="px-1">&middot;</span>
<span class="text-sm text-gray-500">5d ago</span>
</div>
<div class="mt-2 text-sm text-gray-700">
<%= link_to '#', class: '' do %>
<div class="grid grid-cols-3 bg-white rounded hover:shadow-lg">
<div class="col-span-1">
<%= image_tag Character.last.random_image_including_private, class: 'w-full h-full rounded-l' %>
</div>
<div class="col-span-2 pl-4 pt-4 border-l-4 border-teal-500">
<h3 class="text-lg mb-4 font-bold">
<i class="material-icons <%= Document.text_color %> float-left mr-2"><%= Document.icon %></i>
Document name
</h3>
Details or description here
</div>
</div>
<% end %>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
<!-- Feed Content -->
<% if @feed.empty? %>
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-12 text-center">
<div class="mb-6">
<div class="mx-auto h-16 w-16 rounded-full bg-gray-100 flex items-center justify-center">
<svg class="h-8 w-8 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"/>
</svg>
</div>
</div>
<h3 class="text-xl font-semibold text-gray-900 mb-3">No posts here yet!</h3>
<p class="text-gray-600 mb-6 max-w-md mx-auto leading-relaxed">
<%= request.path == stream_path ?
"Follow other worldbuilders to see their amazing creations appear here." :
"Be the first to share something amazing with the community!" %>
</p>
<%= link_to "Discover Creators", users_path, class: "inline-flex items-center px-6 py-3 bg-blue-600 text-white font-semibold rounded-lg shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors" %>
</div>
</main>
<aside class="hidden xl:block xl:col-span-4">
<h2 class="text-gray-400 font-bold text-sm my-4">Pages requesting feedback</h2>
<div>
<ul role="list" class="divide-y divide-gray-200">
<li class="pt-0 pb-2">
<div class="flex space-x-3">
<img class="h-12 w-12 rounded-lg" src="https://images.unsplash.com/photo-1517841905240-472988babdf9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=3&w=256&h=256&q=80" alt="">
<div class="flex-1 space-y-1">
<div class="flex items-center justify-between">
<h3 class="text-sm font-medium">
<i class="material-icons <%= Character.text_color %> float-left text-sm mr-1"><%= Character.icon %></i>
Lindsay Walton
</h3>
<p class="text-sm text-gray-500">1h</p>
</div>
<p class="text-sm text-gray-500">for <strong>general feedback</strong></p>
</div>
</div>
</li>
<li class="py-2">
<div class="flex space-x-3">
<img class="h-12 w-12 rounded-lg" src="https://images.unsplash.com/photo-1517841905240-472988babdf9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=3&w=256&h=256&q=80" alt="">
<div class="flex-1 space-y-1">
<div class="flex items-center justify-between">
<h3 class="text-sm font-medium">
<i class="material-icons <%= Character.text_color %> float-left text-sm mr-1"><%= Character.icon %></i>
Lindsay Walton
</h3>
<p class="text-sm text-gray-500">1h</p>
</div>
<p class="text-sm text-gray-500">for <strong>believability</strong>, <strong>science check</strong></p>
</div>
</div>
</li>
<li class="py-2">
<div class="flex space-x-3">
<img class="h-12 w-12 rounded-lg" src="https://images.unsplash.com/photo-1517841905240-472988babdf9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=3&w=256&h=256&q=80" alt="">
<div class="flex-1 space-y-1">
<div class="flex items-center justify-between">
<h3 class="text-sm font-medium">
<i class="material-icons <%= Character.text_color %> float-left text-sm mr-1"><%= Character.icon %></i>
Lindsay Walton
</h3>
<p class="text-sm text-gray-500">2h</p>
</div>
<p class="text-sm text-gray-500">for <strong>sensitivity</strong></p>
</div>
</div>
</li>
<!-- More items... -->
</ul>
<% else %>
<div class="space-y-6">
<% @feed.each_with_index do |share, index| %>
<%= render partial: 'stream/feed_item', locals: { share: share, is_last: index == @feed.length - 1 } %>
<% end %>
</div>
<h2 class="text-gray-400 font-bold text-sm mt-4 mb-2">Discussions happening now</h2>
<div class="space-y-1">
<div class="ml-1">
<a href="#" class="relative inline-flex items-center rounded-full border border-gray-300 px-3 py-1 text-sm bg-blue-500 hover:bg-blue-400 hover:shadow-lg">
<i class="material-icons float-left text-white">forum</i>
<span class="ml-3.5 font-medium text-white">What is the name of that guy who did the thing?</span>
</a>
</div>
<div class="ml-1">
<a href="#" class="relative inline-flex items-center rounded-full border border-gray-300 px-3 py-1 text-sm bg-blue-500 hover:bg-blue-400 hover:shadow-lg">
<i class="material-icons float-left text-white">forum</i>
<span class="ml-3.5 font-medium text-white">What is your favorite crayon to write on rocks with?</span>
</a>
</div>
<div class="ml-1">
<a href="#" class="relative inline-flex items-center rounded-full border border-gray-300 px-3 py-1 text-sm bg-blue-500 hover:bg-blue-400 hover:shadow-lg">
<i class="material-icons float-left text-white">forum</i>
<span class="ml-3.5 font-medium text-white">How 2 write good</span>
</a>
</div>
<div class="ml-1">
<a href="#" class="relative inline-flex items-center rounded-full border border-gray-300 px-3 py-1 text-sm bg-blue-500 hover:bg-blue-400 hover:shadow-lg">
<i class="material-icons float-left text-white">forum</i>
<span class="ml-3.5 font-medium text-white">DAE hate the new design?</span>
</a>
</div>
<!-- Load More -->
<div class="mt-12 text-center">
<button class="inline-flex items-center px-6 py-3 bg-white border border-gray-200 text-gray-700 font-medium rounded-lg shadow-sm hover:shadow-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all duration-200">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
</svg>
Load more posts
</button>
</div>
<h2 class="text-gray-400 font-bold text-sm mt-4 mb-2">Newest discussion</h2>
<div class="space-y-1">
<div class="ml-1">
<a href="#" class="relative inline-flex items-center rounded-full border border-gray-300 px-3 py-1 text-sm bg-blue-500 hover:bg-blue-400 hover:shadow-lg">
<i class="material-icons float-left text-white">forum</i>
<span class="ml-3.5 font-medium text-white">how do i get in contact with cashapp support</span>
</a>
</div>
</div>
</aside>
<% end %>
</div>
</div>
</div>
<script>
// Disable MaterializeCSS initialization for Tailwind-styled forms
document.addEventListener('DOMContentLoaded', function() {
// Prevent MaterializeCSS from initializing on Tailwind select elements
if (window.M && window.M.FormSelect) {
document.querySelectorAll('.tailwind-styled-form select').forEach(function(select) {
select.classList.add('no-autoinit');
});
}
// Handle collapsible share form
const shareCtaCollapsed = document.getElementById('share-cta-collapsed');
const shareFormExpanded = document.getElementById('share-form-expanded');
const closeShareForm = document.getElementById('close-share-form');
if (shareCtaCollapsed) {
shareCtaCollapsed.addEventListener('click', function() {
shareCtaCollapsed.classList.add('hidden');
shareFormExpanded.classList.remove('hidden');
});
}
if (closeShareForm) {
closeShareForm.addEventListener('click', function() {
shareFormExpanded.classList.add('hidden');
shareCtaCollapsed.classList.remove('hidden');
});
}
});
</script>
<br />
<%= render partial: 'notice_dismissal/messages/12' %>
<div class="row">
<div class="col s12">
<%= render partial: 'content_page_shares/form' %>
</div>
</div>
<%= render partial: 'stream/share', collection: @feed %>
<% if @feed.empty? %>
<div class="row">
<div class='col s12'>
<div class="hoverable card">
<div class="card-content">
<p class="card-title">
There are no posts here yet!
</p>
<p>
You can follow other worldbuilders from their profiles.
Whenever a user you follow shares one of their public pages,
it will appear here for you to comment on!
</p>
</div>
</div>
</div>
</div>
<% end %>
<%= render partial: 'javascripts/content_linking' %>