mirror of
https://github.com/indentlabs/notebook.git
synced 2025-10-26 11:19:22 +00:00
dashboard polish
This commit is contained in:
parent
a0f860d89e
commit
4e07ad8a9b
@ -184,6 +184,10 @@ class User < ApplicationRecord
|
||||
Rails.application.config.content_types[:all].select { |c| can_create? c }
|
||||
end
|
||||
|
||||
def words_written_today
|
||||
word_count_updates.where(created_at: Time.current.beginning_of_day..Time.current.end_of_day).sum(:word_count)
|
||||
end
|
||||
|
||||
# as_json creates a hash structure, which you then pass to ActiveSupport::json.encode to actually encode the object as a JSON string.
|
||||
# This is different from to_json, which converts it straight to an escaped JSON string,
|
||||
# which is undesireable in a case like this, when we want to modify it
|
||||
|
||||
@ -2,10 +2,10 @@
|
||||
<% (@activated_content_types + ["Timeline", "Document"]).each do |content_type| %>
|
||||
<% klass = content_class_from_name(content_type) %>
|
||||
<%= link_to send("new_#{content_type.downcase}_path") do %>
|
||||
<li class="col-span-1 <%= klass.color %> text-white py-6 rounded-lg shadow hover:shadow-lg hover:opacity-80">
|
||||
<div class="w-full text-center">
|
||||
<i class="material-icons text-6xl"><%= klass.icon %></i>
|
||||
<div>
|
||||
<li class="fancy-button relative overflow-hidden col-span-1 <%= klass.color %> text-white py-6 rounded-lg shadow hover:shadow-lg hover:opacity-90 hover:-translate-y-1 transition-all duration-200 active:scale-95 active:shadow-sm cursor-pointer">
|
||||
<div class="w-full text-center relative z-10">
|
||||
<i class="material-icons text-6xl transition-transform duration-200"><%= klass.icon %></i>
|
||||
<div class="transition-all duration-200">
|
||||
<%= content_type %>
|
||||
</div>
|
||||
</div>
|
||||
@ -14,13 +14,136 @@
|
||||
<% end %>
|
||||
|
||||
<%= link_to customization_content_types_path do %>
|
||||
<li class="col-span-1 bg-notebook-blue text-white py-6 rounded-lg shadow hover:shadow-lg">
|
||||
<div class="w-full text-center">
|
||||
<i class="material-icons text-6xl">add</i>
|
||||
<div>
|
||||
<li class="fancy-button relative overflow-hidden col-span-1 bg-notebook-blue text-white py-6 rounded-lg shadow hover:shadow-lg hover:opacity-90 hover:-translate-y-1 transition-all duration-200 active:scale-95 active:shadow-sm cursor-pointer">
|
||||
<div class="w-full text-center relative z-10">
|
||||
<i class="material-icons text-6xl transition-transform duration-200">add</i>
|
||||
<div class="transition-all duration-200">
|
||||
More...
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
.fancy-button {
|
||||
position: relative;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
.fancy-button::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transition: width 0.6s ease, height 0.6s ease;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.fancy-button:active::before {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.fancy-button:active i {
|
||||
transform: scale(1.1) rotate(5deg);
|
||||
}
|
||||
|
||||
.fancy-button:hover i {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* Enhanced glow effect on hover */
|
||||
.fancy-button:hover {
|
||||
filter: brightness(1.1);
|
||||
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.2), 0 10px 10px -5px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Pulse animation on focus */
|
||||
.fancy-button:focus {
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 10px rgba(255, 255, 255, 0);
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(255, 255, 255, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ripple effect styles */
|
||||
.ripple {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
transform: scale(0);
|
||||
animation: rippleEffect 0.6s linear;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@keyframes rippleEffect {
|
||||
to {
|
||||
transform: scale(4);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const fancyButtons = document.querySelectorAll('.fancy-button');
|
||||
|
||||
fancyButtons.forEach(button => {
|
||||
button.addEventListener('click', function(e) {
|
||||
// Create ripple effect
|
||||
const ripple = document.createElement('span');
|
||||
const rect = this.getBoundingClientRect();
|
||||
const size = Math.max(rect.width, rect.height);
|
||||
const x = e.clientX - rect.left - size / 2;
|
||||
const y = e.clientY - rect.top - size / 2;
|
||||
|
||||
ripple.style.width = ripple.style.height = size + 'px';
|
||||
ripple.style.left = x + 'px';
|
||||
ripple.style.top = y + 'px';
|
||||
ripple.classList.add('ripple');
|
||||
|
||||
this.appendChild(ripple);
|
||||
|
||||
// Add click animation classes
|
||||
this.style.transform = 'scale(0.95) translateY(-1px)';
|
||||
|
||||
setTimeout(() => {
|
||||
this.style.transform = '';
|
||||
ripple.remove();
|
||||
}, 300);
|
||||
|
||||
// Add a brief glow effect
|
||||
this.style.boxShadow = '0 0 20px rgba(255, 255, 255, 0.3)';
|
||||
setTimeout(() => {
|
||||
this.style.boxShadow = '';
|
||||
}, 200);
|
||||
});
|
||||
|
||||
// Add floating animation on hover
|
||||
button.addEventListener('mouseenter', function() {
|
||||
this.style.transform = 'translateY(-3px) scale(1.02)';
|
||||
});
|
||||
|
||||
button.addEventListener('mouseleave', function() {
|
||||
this.style.transform = '';
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -48,16 +48,16 @@
|
||||
<!-- Action buttons -->
|
||||
<div class="mt-6 lg:mt-0 flex flex-col sm:flex-row space-y-3 sm:space-y-0 sm:space-x-3">
|
||||
<%= link_to new_character_path do %>
|
||||
<button type="button" class="inline-flex items-center justify-center px-6 py-3 border border-gray-300 shadow-sm text-sm font-medium rounded-lg text-gray-700 bg-white hover:bg-gray-50 hover:border-gray-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-all duration-200">
|
||||
<i class="material-icons mr-2 <%= Character.text_color %>"><%= Character.icon %></i>
|
||||
Create Character
|
||||
<button type="button" class="fancy-button relative overflow-hidden inline-flex items-center justify-center px-6 py-3 border border-gray-300 shadow-sm text-sm font-medium rounded-lg text-gray-700 bg-white hover:bg-gray-50 hover:border-gray-400 hover:shadow-lg hover:-translate-y-0.5 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-all duration-200 active:scale-95 active:shadow-sm">
|
||||
<i class="material-icons mr-2 <%= Character.text_color %> transition-transform duration-200"><%= Character.icon %></i>
|
||||
<span class="transition-all duration-200">Create Character</span>
|
||||
</button>
|
||||
<% end %>
|
||||
<% random_enabled_page_type = (current_user.createable_content_types - [Character]).sample %>
|
||||
<%= link_to new_polymorphic_path(random_enabled_page_type) do %>
|
||||
<button type="button" class="inline-flex items-center justify-center px-6 py-3 border border-transparent shadow-sm text-sm font-medium rounded-lg text-white <%= random_enabled_page_type.color %> focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-all duration-200">
|
||||
<i class="material-icons mr-2"><%= random_enabled_page_type.icon %></i>
|
||||
<span>
|
||||
<button type="button" class="fancy-button relative overflow-hidden inline-flex items-center justify-center px-6 py-3 border border-transparent shadow-sm text-sm font-medium rounded-lg text-white <%= random_enabled_page_type.color %> hover:shadow-lg hover:-translate-y-0.5 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-all duration-200 active:scale-95 active:shadow-sm">
|
||||
<i class="material-icons mr-2 transition-transform duration-200"><%= random_enabled_page_type.icon %></i>
|
||||
<span class="transition-all duration-200">
|
||||
Create <%= random_enabled_page_type.name %>
|
||||
</span>
|
||||
</button>
|
||||
@ -111,4 +111,140 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.fancy-button {
|
||||
position: relative;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
.fancy-button::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transition: width 0.6s ease, height 0.6s ease;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.fancy-button:active::before {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.fancy-button:active i {
|
||||
transform: scale(1.1) rotate(5deg);
|
||||
}
|
||||
|
||||
.fancy-button:hover i {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* Enhanced glow effect on hover */
|
||||
.fancy-button:hover {
|
||||
filter: brightness(1.05);
|
||||
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
/* Pulse animation on focus */
|
||||
.fancy-button:focus {
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 10px rgba(59, 130, 246, 0);
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(59, 130, 246, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Subtle background animation */
|
||||
.fancy-button {
|
||||
background-size: 200% 200%;
|
||||
animation: gradientShift 4s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes gradientShift {
|
||||
0% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const fancyButtons = document.querySelectorAll('.fancy-button');
|
||||
|
||||
fancyButtons.forEach(button => {
|
||||
button.addEventListener('click', function(e) {
|
||||
// Create ripple effect
|
||||
const ripple = document.createElement('span');
|
||||
const rect = this.getBoundingClientRect();
|
||||
const size = Math.max(rect.width, rect.height);
|
||||
const x = e.clientX - rect.left - size / 2;
|
||||
const y = e.clientY - rect.top - size / 2;
|
||||
|
||||
ripple.style.width = ripple.style.height = size + 'px';
|
||||
ripple.style.left = x + 'px';
|
||||
ripple.style.top = y + 'px';
|
||||
ripple.classList.add('ripple');
|
||||
|
||||
this.appendChild(ripple);
|
||||
|
||||
// Add click animation classes
|
||||
this.style.transform = 'scale(0.95)';
|
||||
|
||||
setTimeout(() => {
|
||||
this.style.transform = '';
|
||||
ripple.remove();
|
||||
}, 300);
|
||||
|
||||
// Add a brief glow effect
|
||||
this.style.boxShadow = '0 0 20px rgba(59, 130, 246, 0.5)';
|
||||
setTimeout(() => {
|
||||
this.style.boxShadow = '';
|
||||
}, 200);
|
||||
});
|
||||
|
||||
// Add floating animation on hover
|
||||
button.addEventListener('mouseenter', function() {
|
||||
this.style.transform = 'translateY(-2px) scale(1.02)';
|
||||
});
|
||||
|
||||
button.addEventListener('mouseleave', function() {
|
||||
this.style.transform = '';
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.ripple {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
transform: scale(0);
|
||||
animation: rippleEffect 0.6s linear;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@keyframes rippleEffect {
|
||||
to {
|
||||
transform: scale(4);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<%= render partial: 'javascripts/content_linking' %>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user