summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-06-23 18:04:37 +0200
committererdgeist <erdgeist@erdgeist.org>2026-06-23 18:04:37 +0200
commit6424e10be5a89f175a74c71c55660412a169b8b8 (patch)
treeae8c8111bd1e8c6e82c0a5f9a2c4b088c92bafe5
parent375ed745052148faeb34763087fe04214105f1b8 (diff)
Update deployed state to what's currently running
-rw-r--r--Rakefile4
-rw-r--r--app/controllers/nodes_controller.rb1
-rw-r--r--app/helpers/admin_helper.rb4
-rw-r--r--app/helpers/content_helper.rb6
-rw-r--r--app/models/node.rb29
-rw-r--r--app/models/page.rb15
-rw-r--r--app/views/admin/index.html.erb18
-rw-r--r--app/views/content/_featured_articles.html.erb6
-rw-r--r--app/views/content/_main_navigation.html.erb6
-rw-r--r--app/views/content/_search.html.erb9
-rw-r--r--app/views/content/_tags.html.erb4
-rw-r--r--app/views/layouts/application.html.erb43
-rw-r--r--app/views/nodes/edit.html.erb156
-rw-r--r--config/database.mysql-sample.yml45
-rw-r--r--config/database.psql-sample.yml51
-rw-r--r--config/environments/production.rb2
-rw-r--r--config/locales/de.yml1
-rw-r--r--config/locales/en.yml6
-rw-r--r--public/javascripts/public.js9
-rw-r--r--public/stylesheets/admin.css202
-rw-r--r--public/stylesheets/ccc.css363
-rw-r--r--test/functional/nodes_controller_test.rb36
-rw-r--r--vendor/plugins/paperclip/lib/paperclip/geometry.rb1
23 files changed, 637 insertions, 380 deletions
diff --git a/Rakefile b/Rakefile
index 3af2c3a..b8e1d62 100644
--- a/Rakefile
+++ b/Rakefile
@@ -5,7 +5,9 @@ require(File.join(File.dirname(__FILE__), 'config', 'boot'))
5 5
6require 'rake' 6require 'rake'
7require 'rake/testtask' 7require 'rake/testtask'
8require 'rake/rdoctask' 8
9#require 'rake/rdoctask'
10#require 'rdoc/task'
9 11
10require 'tasks/rails' 12require 'tasks/rails'
11require 'thinking_sphinx/tasks' 13require 'thinking_sphinx/tasks'
diff --git a/app/controllers/nodes_controller.rb b/app/controllers/nodes_controller.rb
index b8cd644..95aed48 100644
--- a/app/controllers/nodes_controller.rb
+++ b/app/controllers/nodes_controller.rb
@@ -55,6 +55,7 @@ class NodesController < ApplicationController
55 55
56 def show 56 def show
57 node = Node.find(params[:id]) 57 node = Node.find(params[:id])
58 node.wipe_draft!
58 @page = node.draft || node.head 59 @page = node.draft || node.head
59 end 60 end
60 61
diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb
index 232862b..389f6dc 100644
--- a/app/helpers/admin_helper.rb
+++ b/app/helpers/admin_helper.rb
@@ -3,9 +3,9 @@ module AdminHelper
3 def language_selector 3 def language_selector
4 case I18n.locale 4 case I18n.locale
5 when :de 5 when :de
6 link_to 'English (Aktiv: Deutsch)', url_for(:overwrite_params => {:locale => :en}) 6 link_to raw('<span class="inactive">English</span>'), url_for(:overwrite_params => {:locale => :en})
7 when :en 7 when :en
8 link_to 'Deutsch (Active: English)', url_for(:overwrite_params => {:locale => :de}) 8 link_to raw('<span class="inactive">Deutsch</span>'), url_for(:overwrite_params => {:locale => :de})
9 end 9 end
10 end 10 end
11end 11end
diff --git a/app/helpers/content_helper.rb b/app/helpers/content_helper.rb
index 7286976..17364f8 100644
--- a/app/helpers/content_helper.rb
+++ b/app/helpers/content_helper.rb
@@ -43,7 +43,7 @@ module ContentHelper
43 # Returns the published_at attribute of a page if it is not nil, otherwise 43 # Returns the published_at attribute of a page if it is not nil, otherwise
44 # it returns the auto-filled value of the created_at attribute 44 # it returns the auto-filled value of the created_at attribute
45 def date_for_page page 45 def date_for_page page
46 page.published_at.to_s(:db) rescue page.created_at.to_s(:db) 46 I18n.l(page.published_at, :format => :ccc) rescue I18n.l(page.created_at, :format => :ccc)
47 end 47 end
48 48
49 def author_for_page page 49 def author_for_page page
@@ -80,10 +80,10 @@ module ContentHelper
80 begin 80 begin
81 if content =~ /<aggregate([^<>]*)>/ 81 if content =~ /<aggregate([^<>]*)>/
82 tag = $~.to_s 82 tag = $~.to_s
83 matched_data = $1.scan(/\w+\=\"[a-zA-Z\s\/_\d,]*\"/) 83 matched_data = $1.scan(/\w+\=\"[a-zA-Z\s\/_\d,.=]*\"/)
84 84
85 matched_data.each do |data| 85 matched_data.each do |data|
86 splitted_data = data.split("=") 86 splitted_data = data.split("=", 2)
87 options[splitted_data[0].to_sym] = splitted_data[1].gsub(/\"/, "") 87 options[splitted_data[0].to_sym] = splitted_data[1].gsub(/\"/, "")
88 end 88 end
89 89
diff --git a/app/models/node.rb b/app/models/node.rb
index 6c11fed..75122d1 100644
--- a/app/models/node.rb
+++ b/app/models/node.rb
@@ -3,11 +3,11 @@ class Node < ActiveRecord::Base
3 acts_as_nested_set 3 acts_as_nested_set
4 4
5 # Associations 5 # Associations
6 has_many :pages, :order => "revision ASC" 6 has_many :pages, :order => "revision ASC", :dependent => :destroy
7 belongs_to :head, :class_name => "Page", :foreign_key => :head_id 7 belongs_to :head, :class_name => "Page", :foreign_key => :head_id, :dependent => :destroy
8 belongs_to :draft, :class_name => "Page", :foreign_key => :draft_id 8 belongs_to :draft, :class_name => "Page", :foreign_key => :draft_id, :dependent => :destroy
9 has_many :permissions 9 has_many :permissions, :dependent => :destroy
10 has_one :event 10 has_one :event, :dependent => :destroy
11 belongs_to :lock_owner, :class_name => "User", :foreign_key => :locking_user_id 11 belongs_to :lock_owner, :class_name => "User", :foreign_key => :locking_user_id
12 12
13 # Callbacks 13 # Callbacks
@@ -60,6 +60,7 @@ class Node < ActiveRecord::Base
60 # Instance Methods 60 # Instance Methods
61 61
62 def find_or_create_draft current_user 62 def find_or_create_draft current_user
63 self.wipe_draft!
63 if draft && self.lock_owner == current_user 64 if draft && self.lock_owner == current_user
64 draft 65 draft
65 elsif draft && self.lock_owner.nil? 66 elsif draft && self.lock_owner.nil?
@@ -115,6 +116,24 @@ class Node < ActiveRecord::Base
115 end 116 end
116 end 117 end
117 118
119 # removes a draft and the lock if it is older than a day and still
120 # identical to head
121 def wipe_draft!
122 unless self.draft
123 self.unlock!
124 return
125 end
126 return unless self.head
127 return unless self.draft.updated_at < 1.day.ago
128 return if Page.find(self.head).has_changes_to? self.draft
129
130 self.draft.destroy
131 self.draft_id = nil
132 self.unlock!
133 self.save!
134 self.reload
135 end
136
118 def restore_revision! revision 137 def restore_revision! revision
119 if page = self.pages.find_by_revision(revision) 138 if page = self.pages.find_by_revision(revision)
120 self.head = page 139 self.head = page
diff --git a/app/models/page.rb b/app/models/page.rb
index 0cfad53..f804353 100644
--- a/app/models/page.rb
+++ b/app/models/page.rb
@@ -64,7 +64,7 @@ class Page < ActiveRecord::Base
64 64
65 Page.heads.paginate( 65 Page.heads.paginate(
66 find_options_for_find_tagged_with( 66 find_options_for_find_tagged_with(
67 options[:tags].gsub(/\s/, ","), :match_all => true 67 options[:tags].gsub(/\s/, ","), :match_all => true, :conditions => options[:conditions]
68 ).merge( 68 ).merge(
69 :page => page, 69 :page => page,
70 :per_page => options[:limit], 70 :per_page => options[:limit],
@@ -94,6 +94,19 @@ class Page < ActiveRecord::Base
94 end 94 end
95 end 95 end
96 96
97 # Is used to compare a node's head with the node's draft
98
99 def has_changes_to? draft
100 return true unless node == draft.node
101 return true unless assets == draft.assets
102 return true unless tag_list == draft.tag_list
103 return true unless template_name == draft.template_name
104 return true unless translated_locales.sort_by(&:to_s) == draft.translated_locales.sort_by(&:to_s)
105 changed = false
106 translated_locales.each { |locale| I18n.with_locale(locale) { changed = true unless title == draft.title && abstract == draft.abstract && body == draft.body } }
107 return changed
108 end
109
97 # Instance Methods 110 # Instance Methods
98 111
99 def public_template_path 112 def public_template_path
diff --git a/app/views/admin/index.html.erb b/app/views/admin/index.html.erb
index edad1d6..2741db3 100644
--- a/app/views/admin/index.html.erb
+++ b/app/views/admin/index.html.erb
@@ -1,14 +1,14 @@
1<div id="admin_wizard"> 1<div id="admin_wizard">
2 <%= link_to 'Create Update or Pressemitteilung', new_node_path, :only_path => false %> 2 <div class="admin_wizard_button"><%= link_to 'Create Update or Pressemitteilung', new_node_path, :only_path => false %></div>
3 <a href="#" id="admin_wizard_my_work" class="admin_wizard_button button">Continue my work</a> 3 <div class="admin_wizard_button"><a href="#" id="admin_wizard_my_work" class="button">Continue my work</a></div>
4 <a href="#" id="admin_wizard_create_page" class="admin_wizard_button button">Add a page in the page tree</a> 4 <div class="admin_wizard_button"><a href="#" id="admin_wizard_create_page" class="button">Add a page in the page tree</a></div>
5 <%= link_to("Upload a new asset", new_asset_path, :only_path => false) %> 5 <div class="admin_wizard_button"><%= link_to("Upload a new asset", new_asset_path, :only_path => false) %></div>
6</div> 6</div>
7 7
8<p id="overview_toggle"> 8<p id="overview_toggle">
9 <a href="#" id="recent_changes_toggle" class="button">recent changes</a> 9 <a href="#" id="recent_changes_toggle" class="button">recent changes</a>
10 <a href="#" id="my_work_toggle" class="button">my work</a> 10 <a href="#" id="my_work_toggle" class="button">my work</a>
11 <a href="#" id="current_drafts_toggle" class="button">current drafts</a> 11 <a href="#" id="current_drafts_toggle" class="button">current drafts (<%= @drafts_count %>)</a>
12 <a href="#" id="admin_sitemap_toggle" class="button">site map</a> 12 <a href="#" id="admin_sitemap_toggle" class="button">site map</a>
13</p> 13</p>
14 14
@@ -39,7 +39,7 @@
39 <%= node.lock_owner.login if node.lock_owner %> 39 <%= node.lock_owner.login if node.lock_owner %>
40 </td> 40 </td>
41 <td> 41 <td>
42 <%= node.draft ? node.draft.revision : node.head.revision %> 42 <%= link_to ( node.draft ? node.draft.revision : (node.head ? node.head.revision : "EMPTY" ) ), node_revisions_path(node) %>
43 </td> 43 </td>
44 </tr> 44 </tr>
45 <% end %> 45 <% end %>
@@ -73,7 +73,7 @@
73 <%= node.lock_owner.login if node.lock_owner %> 73 <%= node.lock_owner.login if node.lock_owner %>
74 </td> 74 </td>
75 <td> 75 <td>
76 <%= node.draft ? node.draft.revision : node.head.revision %> 76 <%= link_to ( node.draft ? node.draft.revision : (node.head ? node.head.revision : "EMPTY" ) ), node_revisions_path(node) %>
77 </td> 77 </td>
78 </tr> 78 </tr>
79 <% end %> 79 <% end %>
@@ -107,7 +107,7 @@
107 <%= node.lock_owner.login if node.lock_owner %> 107 <%= node.lock_owner.login if node.lock_owner %>
108 </td> 108 </td>
109 <td> 109 <td>
110 <%= node.draft ? node.draft.revision : ( node.head ? node.head.revision : "EMPTY" ) %> 110 <%= link_to ( node.draft ? node.draft.revision : (node.head ? node.head.revision : "EMPTY" ) ), node_revisions_path(node) %>
111 </td> 111 </td>
112 </tr> 112 </tr>
113 <% end %> 113 <% end %>
@@ -135,7 +135,7 @@
135 </td> 135 </td>
136 <td class="actions"> 136 <td class="actions">
137 <%= link_to 'create subpage', new_node_path(:parent_id => node.id) %> 137 <%= link_to 'create subpage', new_node_path(:parent_id => node.id) %>
138 <%= link_to ':: Revisions', node_revisions_path(node) %> 138 <%= link_to 'Revisions', node_revisions_path(node) %>
139 </td> 139 </td>
140 <td> 140 <td>
141 <%= node.lock_owner.login if node.lock_owner %> 141 <%= node.lock_owner.login if node.lock_owner %>
diff --git a/app/views/content/_featured_articles.html.erb b/app/views/content/_featured_articles.html.erb
index 0220abb..c69911f 100644
--- a/app/views/content/_featured_articles.html.erb
+++ b/app/views/content/_featured_articles.html.erb
@@ -11,7 +11,7 @@
11 11
12 <%= link_to( 12 <%= link_to(
13 image_tag( 'chaosradio.png' ), 13 image_tag( 'chaosradio.png' ),
14 "http://chaosradio.ccc.de/", 14 "https://chaosradio.ccc.de/",
15 :id => "chaosradio_icon", 15 :id => "chaosradio_icon",
16 :title => "Chaosradio" 16 :title => "Chaosradio"
17 )%> 17 )%>
@@ -25,14 +25,14 @@
25 25
26 <%= link_to( 26 <%= link_to(
27 image_tag( 'ds.png' ), 27 image_tag( 'ds.png' ),
28 "http://ds.ccc.de/", 28 "https://ds.ccc.de/",
29 :id => "ds_icon", 29 :id => "ds_icon",
30 :title => "Datenschleuder" 30 :title => "Datenschleuder"
31 )%> 31 )%>
32 32
33 <%= link_to( 33 <%= link_to(
34 image_tag( 'events.png' ), 34 image_tag( 'events.png' ),
35 "http://events.ccc.de/", 35 "https://events.ccc.de/",
36 :id => "events_icon", 36 :id => "events_icon",
37 :title => "Events Blog" 37 :title => "Events Blog"
38 )%> 38 )%>
diff --git a/app/views/content/_main_navigation.html.erb b/app/views/content/_main_navigation.html.erb
index a984512..2fe8b77 100644
--- a/app/views/content/_main_navigation.html.erb
+++ b/app/views/content/_main_navigation.html.erb
@@ -3,11 +3,5 @@
3 <% menu_items.each do |item| %> 3 <% menu_items.each do |item| %>
4 <li><%= link_to_path item.title, item.path %></li> 4 <li><%= link_to_path item.title, item.path %></li>
5 <% end %> 5 <% end %>
6 <li>
7 <%= language_selector %>
8 </li>
9 <li id="light-mode-li">
10 <input id="light-mode" type="checkbox" /><label for="light-mode">lights on</label>
11 </li>
12 </ul> 6 </ul>
13</div> 7</div>
diff --git a/app/views/content/_search.html.erb b/app/views/content/_search.html.erb
index 9f61042..e654462 100644
--- a/app/views/content/_search.html.erb
+++ b/app/views/content/_search.html.erb
@@ -1,8 +1,3 @@
1<% form_tag search_path, :method => 'get' do %> 1<% form_tag search_path, :method => 'get' do %>
2<table> 2 <div><%= text_field_tag :search_term, params[:search_term], :placeholder => 'suchen', :type => 'search' %></div>
3 <tr> 3<% end %>
4 <td><%= text_field_tag :search_term, params[:search_term] %></td>
5 <td style="padding-top: 2px"><%= image_submit_tag("search_button.png") %></td>
6 </tr>
7</table>
8<% end %> \ No newline at end of file
diff --git a/app/views/content/_tags.html.erb b/app/views/content/_tags.html.erb
index d33bc10..fd808b6 100644
--- a/app/views/content/_tags.html.erb
+++ b/app/views/content/_tags.html.erb
@@ -1,3 +1,4 @@
1<% unless @page.tags.empty? %>
1<div id="tags"> 2<div id="tags">
2 <h2>Tags</h2> 3 <h2>Tags</h2>
3 <ul class="teasertext"> 4 <ul class="teasertext">
@@ -5,4 +6,5 @@
5 <li><%= link_to tag.name, tag_path(:id => tag.name) %></li> 6 <li><%= link_to tag.name, tag_path(:id => tag.name) %></li>
6 <% end %> 7 <% end %>
7 </ul> 8 </ul>
8</div> \ No newline at end of file 9</div>
10<% end %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 915091d..d2a624f 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -1,11 +1,10 @@
1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 1<!DOCTYPE HTML>
2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 2
4<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 3<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5 <head> 4 <head>
6 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7 <meta name="viewport" content="width=device-width,initial-scale=1"/> 6 <meta name="viewport" content="width=device-width,initial-scale=1"/>
8 <meta name="description" content="Der Chaos Computer Club ist eine galaktische Gemeinschaft von Lebewesen für Informationsfreiheit und Technikfolgenabschätzung."> 7 <meta name="description" content="Der Chaos Computer Club ist eine galaktische Gemeinschaft von Lebewesen für Informationsfreiheit und Technikfolgenabschätzung."/>
9 8
10 <meta property="og:image" content="https://www.ccc.de/images/chaosknoten.svg" /> 9 <meta property="og:image" content="https://www.ccc.de/images/chaosknoten.svg" />
11 <meta property="og:description" content="Der Chaos Computer Club ist eine galaktische Gemeinschaft von Lebewesen für Informationsfreiheit und Technikfolgenabschätzung." /> 10 <meta property="og:description" content="Der Chaos Computer Club ist eine galaktische Gemeinschaft von Lebewesen für Informationsfreiheit und Technikfolgenabschätzung." />
@@ -19,21 +18,45 @@
19 18
20 <%= auto_discovery_link_tag(:atom, {:locale => :de, :controller => "rss", :action => "updates", :format => :xml}) %> 19 <%= auto_discovery_link_tag(:atom, {:locale => :de, :controller => "rss", :action => "updates", :format => :xml}) %>
21 <%= auto_discovery_link_tag(:rss, {:locale => :de, :controller => "rss", :action => "updates", :format => :rdf}) %> 20 <%= auto_discovery_link_tag(:rss, {:locale => :de, :controller => "rss", :action => "updates", :format => :rdf}) %>
21
22 <script>
23 (function() { document.addEventListener("DOMContentLoaded", function() {
24 if (localStorage.getItem('override-prefers-color-scheme', false))
25 document.getElementById("light-mode").checked = true;
26 }); })();
27 </script>
28
22 </head> 29 </head>
23 30
24 <body lang="<%= @page.effective_lang %>"> 31 <body lang="<%= @page.effective_lang %>">
25 <div id="wrapper"> 32 <div id="wrapper">
26 <div id="header"> 33 <div id="header">
27 <%= link_to_path(image_tag("header.png"), "/home") %> 34 <%= image_tag("header.png") %>
35 <!-- <%= link_to_path(image_tag("header.png"), "/home") %> -->
28 </div> 36 </div>
29 <div id="search"> 37 <div id="toolbox">
30 <%= render :partial => "content/search" %> 38 <div id="search">
39 <%= render :partial => "content/search" %>
40 </div>
41 <div id="light-mode-div">
42 <input id="light-mode" type="checkbox" aria-label="Switch between dark and light mode" /><label for="light-mode"><span class="hide-me">lights</span></label>
43 </div>
44 <div id="burger-div">
45 <input type="checkbox" id="menu-toggle" class="menu-checkbox">
46 <label for="menu-toggle" class="burger-menu"><span></span><span></span><span></span></label>
47 </div>
31 </div> 48 </div>
32 <div id="left_column"> 49 <div id="left_column">
33 <%= main_menu %> 50 <%= main_menu %>
34 51
35 <% if current_user && @page.node %> 52 <% if current_user && @page.node %>
36 <%= link_to "Edit", node_path(:id => @page.node) %> 53 <div class="main_navigation">
54 <h2>Admin</h2>
55 <ul>
56 <li><%= link_to raw('<span class="inactive admin_edit_link">⚙️ Overview</span>'),:controller => :admin, :action => 'index' %></li>
57 <li><%= link_to raw('<span class="inactive admin_edit_link">✎ Edit</span>'), node_path(:id => @page.node) %></li>
58 </ul>
59 </div>
37 <% end %> 60 <% end %>
38 61
39 <%= calendar %> 62 <%= calendar %>
@@ -42,9 +65,11 @@
42 <%= yield :layout %> 65 <%= yield :layout %>
43 <div id="footer"> 66 <div id="footer">
44 <br /> 67 <br />
45 <br />
46 <p style="text-align: center"> 68 <p style="text-align: center">
47 <%= link_to t(:sponsors), content_path("sponsors") %> 69 <%= link_to "Impressum", content_path("imprint") %>
70 <%= link_to "Datenschutz", content_path("datenschutz") %>
71 <%= language_selector %>
72 <!-- %= link_to t(:sponsors), content_path("sponsors") % -->
48 </p> 73 </p>
49 </div> 74 </div>
50 </div> 75 </div>
diff --git a/app/views/nodes/edit.html.erb b/app/views/nodes/edit.html.erb
index ee11047..612a3d3 100644
--- a/app/views/nodes/edit.html.erb
+++ b/app/views/nodes/edit.html.erb
@@ -11,100 +11,76 @@
11 <%= f.error_messages %> 11 <%= f.error_messages %>
12 12
13 <div id="metadata"> 13 <div id="metadata">
14 <table> 14 <div class="node_description">Event</div>
15 <tr> 15 <div class="node_content"><%= event_information %></div>
16 <td class="description">Event</td>
17 <td><%= event_information %></td>
18 </tr>
19 <tr>
20 <td class="description">Slug</td>
21 <td>
22 <%=
23 f.text_field(
24 :staged_slug, :value => @node.staged_slug || @node.slug
25 )
26 %>
27 </td>
28 </tr>
29 <tr>
30 <td class="description">parent</td>
31 <td>
32 <%= text_field_tag :move_to_search_term, @node.parent.title rescue "" %>
33 <div id="search_results">
34 16
35 </div> 17 <div class="node_description">Slug</div>
36 <%= f.hidden_field( 18 <div class="node_content">
37 :staged_parent_id, 19 <%= f.text_field(
38 :value => @node.staged_parent_id || @node.parent_id 20 :staged_slug, :value => @node.staged_slug || @node.slug
39 ) 21 )
40 %> 22 %>
41 </td> 23 </div>
42 </tr> 24
25 <div class="node_description">parent</div>
26 <div class="node_content">
27 <%= text_field_tag :move_to_search_term, @node.parent.title rescue "" %>
28 <div id="search_results">
29
30 </div>
31 <%= f.hidden_field(
32 :staged_parent_id,
33 :value => @node.staged_parent_id || @node.parent_id
34 )
35 %>
36 </div>
43 37
44 <% fields_for @draft do |d| %> 38 <% fields_for @draft do |d| %>
45 <tr> 39 <div class="node_description">Tags - comma seperated</div>
46 <td class="description">Tags - comma seperated</td> 40 <div class="node_content"><%= text_field_tag :tag_list, @draft.tag_list %></div>
47 <td><%= text_field_tag :tag_list, @draft.tag_list %></td> 41
48 </tr> 42 <div class="node_description">Publish at</div>
49 <tr> 43 <div class="node_content"><%= d.datetime_select :published_at, :value => @draft.published_at %></div>
50 <td class="description">Publish at</td> 44
51 <td><%= d.datetime_select :published_at, :value => @draft.published_at %></td> 45 <div class="node_description">Template</div>
52 </tr> 46 <div class="node_content"><%= d.select :template_name, custom_page_templates, {:prompt => 'Select Template'} %></div>
53 <tr> 47
54 <td class="description">Template</td> 48 <div class="node_description">Author</div>
55 <td><%= d.select :template_name, custom_page_templates, {:prompt => 'Select Template'} %></td> 49 <div class="node_content"><%= d.select :user_id, user_list %></div>
56 </tr> 50
57 <tr> 51 <div class="node_description">Images</div>
58 <td class="description">Author</td> 52 <div class="node_content">
59 <td><%= d.select :user_id, user_list %></td> 53 <ul id="image_box" rel="<%= @draft.id %>">
60 </tr> 54 <% @draft.assets.images.each do |image| %>
61 <tr> 55 <li rel="images_<%= image.id %>">
62 <td class="description">Images</td> 56 <%= image_tag(image.upload.url(:thumb)) %>
63 <td> 57 </li>
64 <ul id="image_box" rel="<%= @draft.id %>"> 58 <% end %>
65 <% @draft.assets.images.each do |image| %> 59 </ul>
66 <li rel="images_<%= image.id %>"> 60 <div class="clear_left right">
67 <%= image_tag(image.upload.url(:thumb)) %> 61 <a id="image_browser_toggle" class="unselected" href="#">image browser</a>
68 </li> 62 </div>
69 <% end %> 63 <div id="image_browser">
70 </ul> 64 <ul>
71 <div class="clear_left right"> 65 <% Asset.images.each do |image| %>
72 <a id="image_browser_toggle" class="unselected" href="#">image browser</a> 66 <li rel="images_<%= image.id %>"><%= image_tag(image.upload.url(:thumb)) %></li>
73 </div> 67 <% end %>
74 <div id="image_browser"> 68 </ul>
75 <ul> 69 </div>
76 <% Asset.images.each do |image| %> 70 </div>
77 <li rel="images_<%= image.id %>"><%= image_tag(image.upload.url(:thumb)) %></li>
78 <% end %>
79 </ul>
80 </div>
81 </td>
82 </tr>
83 </table>
84 </div> 71 </div>
85 72
86 <table id="content"> 73 <div id="content">
87 <tr> 74 <div class="node_description">Title</div>
88 <th class="description"></th> 75 <div class="node_content"><%= d.text_field :title, :pattern => "(?:[^<>&amp;]|&amp;amp;|&amp;lt;|&amp;gt;)*", :title => "Warning: Unescaped HTML entities detected! Use &amp;lt;, &amp;gt;, &amp;amp; instead of <, >, &." %></div>
89 <th class="content"></th> 76
90 </tr> 77 <div class="node_description">Abstract</div>
91 <tr> 78 <div class="node_content"><%= d.text_area :abstract %></div>
92 <td class="description">Title</td> 79
93 <td><%= d.text_field :title, :pattern => "(?:[^<>&amp;]|&amp;amp;|&amp;lt;|&amp;gt;)*", :title => "Warning: Unescaped HTML entities detected! Use &amp;lt;, &amp;gt;, &amp;amp; instead of <, >, &." %></td> 80 <div class="node_description">Body</div>
94 </tr> 81 <div class="node_content"><%= d.text_area :body, :class => 'with_editor' %></div>
95 <tr> 82
96 <td class="description">Abstract</td> 83 <div><%= d.submit 'save' %></div>
97 <td><%= d.text_area :abstract %></td>
98 </tr>
99 <tr>
100 <td class="description">Body</td>
101 <td><%= d.text_area :body, :class => 'with_editor' %></td>
102 </tr>
103 <tr>
104 <td></td>
105 <td class="right"><%= d.submit 'save' %></td>
106 </tr>
107 </table>
108 <% end %> 84 <% end %>
109<% end %> 85<% end %>
110</div> 86</div>
diff --git a/config/database.mysql-sample.yml b/config/database.mysql-sample.yml
deleted file mode 100644
index bdb5311..0000000
--- a/config/database.mysql-sample.yml
+++ /dev/null
@@ -1,45 +0,0 @@
1# MySQL. Versions 4.1 and 5.0 are recommended.
2#
3# Install the MySQL driver:
4# gem install mysql
5# On Mac OS X:
6# sudo gem install mysql -- --with-mysql-dir=/usr/local/mysql
7# On Mac OS X Leopard:
8# sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
9# This sets the ARCHFLAGS environment variable to your native architecture
10# On Windows:
11# gem install mysql
12# Choose the win32 build.
13# Install MySQL and put its /bin directory on your path.
14#
15# And be sure to use new-style password hashing:
16# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
17development:
18 adapter: mysql
19 encoding: utf8
20 database: mysql_development
21 pool: 5
22 username: root
23 password:
24 socket: /opt/local/var/run/mysql5/mysqld.sock
25
26# Warning: The database defined as "test" will be erased and
27# re-generated from your development database when you run "rake".
28# Do not set this db to the same as development or production.
29test:
30 adapter: mysql
31 encoding: utf8
32 database: mysql_test
33 pool: 5
34 username: root
35 password:
36 socket: /opt/local/var/run/mysql5/mysqld.sock
37
38production:
39 adapter: mysql
40 encoding: utf8
41 database: mysql_production
42 pool: 5
43 username: root
44 password:
45 socket: /opt/local/var/run/mysql5/mysqld.sock
diff --git a/config/database.psql-sample.yml b/config/database.psql-sample.yml
deleted file mode 100644
index db7276e..0000000
--- a/config/database.psql-sample.yml
+++ /dev/null
@@ -1,51 +0,0 @@
1# PostgreSQL. Versions 7.4 and 8.x are supported.
2#
3# Install the ruby-postgres driver:
4# gem install ruby-postgres
5# On Mac OS X:
6# gem install ruby-postgres -- --include=/usr/local/pgsql
7# On Windows:
8# gem install ruby-postgres
9# Choose the win32 build.
10# Install PostgreSQL and put its /bin directory on your path.
11development:
12 adapter: postgresql
13 encoding: unicode
14 database: psql_development
15 pool: 5
16 username: psql
17 password:
18
19 # Connect on a TCP socket. Omitted by default since the client uses a
20 # domain socket that doesn't need configuration. Windows does not have
21 # domain sockets, so uncomment these lines.
22 #host: localhost
23 #port: 5432
24
25 # Schema search path. The server defaults to $user,public
26 #schema_search_path: myapp,sharedapp,public
27
28 # Minimum log levels, in increasing order:
29 # debug5, debug4, debug3, debug2, debug1,
30 # log, notice, warning, error, fatal, and panic
31 # The server defaults to notice.
32 #min_messages: warning
33
34# Warning: The database defined as "test" will be erased and
35# re-generated from your development database when you run "rake".
36# Do not set this db to the same as development or production.
37test:
38 adapter: postgresql
39 encoding: unicode
40 database: psql_test
41 pool: 5
42 username: psql
43 password:
44
45production:
46 adapter: postgresql
47 encoding: unicode
48 database: psql_production
49 pool: 5
50 username: psql
51 password:
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 3195745..1768ab7 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -9,7 +9,7 @@ config.action_controller.consider_all_requests_local = false
9config.action_controller.perform_caching = true 9config.action_controller.perform_caching = true
10 10
11# See everything in the log (default is :info) 11# See everything in the log (default is :info)
12# config.log_level = :debug 12config.log_level = :info
13 13
14# Use a different logger for distributed setups 14# Use a different logger for distributed setups
15# config.logger = SyslogLogger.new 15# config.logger = SyslogLogger.new
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 2663948..fca8c11 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -24,6 +24,7 @@ de:
24 formats: 24 formats:
25 default: "%A, %e. %B %Y, %H:%M Uhr" 25 default: "%A, %e. %B %Y, %H:%M Uhr"
26 short: "%e. %B, %H:%M Uhr" 26 short: "%e. %B, %H:%M Uhr"
27 ccc: "%e. %B %Y, %H:%M Uhr"
27 long: "%A, %e. %B %Y, %H:%M Uhr" 28 long: "%A, %e. %B %Y, %H:%M Uhr"
28 time: "%H:%M" 29 time: "%H:%M"
29 30
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 81fa48e..2458d4d 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -7,4 +7,8 @@ en:
7 sponsors: sponsors 7 sponsors: sponsors
8 hello: "Hello world" 8 hello: "Hello world"
9 show_tag_headline: "Pages tagged with:" 9 show_tag_headline: "Pages tagged with:"
10 old_ccc_de: the old ccc.de \ No newline at end of file 10 old_ccc_de: the old ccc.de
11
12 time:
13 formats:
14 ccc: "%d %B, %Y %H:%M"
diff --git a/public/javascripts/public.js b/public/javascripts/public.js
index 0919360..10f04e8 100644
--- a/public/javascripts/public.js
+++ b/public/javascripts/public.js
@@ -18,6 +18,13 @@ $(document).ready(function(){
18 $("div#headline_image a img").bind("click", function(){ 18 $("div#headline_image a img").bind("click", function(){
19 $(".shadowbox_image:first").trigger("click"); 19 $(".shadowbox_image:first").trigger("click");
20 }); 20 });
21
22 document.getElementById("light-mode").addEventListener("change", () => {
23 if (document.getElementById("light-mode").checked)
24 localStorage.setItem("override-prefers-color-scheme", 1);
25 else
26 localStorage.removeItem("override-prefers-color-scheme");
27 });
21}); 28});
22 29
23 30
@@ -38,4 +45,4 @@ var image_handler = {
38 path = path_name.replace(/\/(de|en)*\/*/, ""); 45 path = path_name.replace(/\/(de|en)*\/*/, "");
39 gallery_path = ""; 46 gallery_path = "";
40 } 47 }
41}; \ No newline at end of file 48};
diff --git a/public/stylesheets/admin.css b/public/stylesheets/admin.css
index c7ebb52..7031f77 100644
--- a/public/stylesheets/admin.css
+++ b/public/stylesheets/admin.css
@@ -2,7 +2,7 @@
2 2
3body { 3body {
4 font-family: Helvetica, Arial, sans-serif; 4 font-family: Helvetica, Arial, sans-serif;
5 font-size: 12px; 5 font-size: 1rem;
6 margin: 0px; 6 margin: 0px;
7} 7}
8 8
@@ -19,15 +19,25 @@ th {
19 text-transform: lowercase; 19 text-transform: lowercase;
20} 20}
21 21
22#metadata,
22#content { 23#content {
23 margin-left: 5px; 24 margin-left: 5px;
24} 25}
25 26
27@media(min-width:1016px) {
28#wrapper {
29 margin: 0 125px;
30}
31}
32@media(max-width:1015px) {
26#wrapper { 33#wrapper {
27 margin-left: 125px; 34 margin: 0;
28 width: 899px; 35 width: 100%;
36 box-sizing: border-box;
37}
29} 38}
30 39
40
31#flash { 41#flash {
32 height: 12px; 42 height: 12px;
33 line-height: 20px; 43 line-height: 20px;
@@ -110,16 +120,24 @@ input[type=submit],
110 margin-bottom: 2rem; 120 margin-bottom: 2rem;
111} 121}
112 122
113#admin_wizard a { 123#page_submit a,
124.admin_wizard_button a {
125 color: white !important;
126}
127
128#page_submit,
129.admin_wizard_button {
130 display: inline-block;
114 font-size: 1rem; 131 font-size: 1rem;
115 font-weight: bold; 132 font-weight: bold;
116 padding: 0.5rem; 133 padding: 0.5rem;
134 margin-bottom: 0.5rem;
117 background-color: green; 135 background-color: green;
118 color: white;
119} 136}
120 137
121#admin_wizard a:hover { 138#page_submit:hover,
122 background-color: lime; 139.admin_wizard_button:hover {
140 background-color: lime !important;
123} 141}
124 142
125#sub_navigation a { 143#sub_navigation a {
@@ -144,21 +162,27 @@ input[type=submit],
144/* Nodes */ 162/* Nodes */
145 163
146table.node_table { 164table.node_table {
147 width: 899px;
148 border-collapse: collapse; 165 border-collapse: collapse;
149} 166}
150 167
151table.node_table tr { 168table.node_table tr {
152 height: 65px; 169 min-height: 2rem;
153 border-bottom: 1px solid #000000; 170 border-bottom: 1px solid #000000;
154} 171}
155 172
173table.node_table th.node_id,
174table.node_table th.revision,
156table.node_table th.title { 175table.node_table th.title {
157 width: 450px; 176 min-width: 4rem;
177}
178
179table.node_table th.editor,
180table.node_table th.title {
181 min-width: 12rem;
158} 182}
159 183
160table.node_table tr.header { 184table.node_table tr.header {
161 height: 20px; 185 height: 2rem;
162 text-align: left; 186 text-align: left;
163} 187}
164 188
@@ -167,6 +191,7 @@ table.node_table td {
167 padding-bottom: 0px; 191 padding-bottom: 0px;
168 padding-right: 25px; 192 padding-right: 25px;
169 padding-left: 0px; 193 padding-left: 0px;
194 min-width: 2rem;
170} 195}
171 196
172table.node_table .node_id { 197table.node_table .node_id {
@@ -232,31 +257,19 @@ table#revisions tr {
232/* Page Editor */ 257/* Page Editor */
233 258
234input[type=text], textarea { 259input[type=text], textarea {
235 font-size: 12px; 260 font-size: 1rem;
236 font-family: Helvetica; 261 font-family: Helvetica;
237 border: 1px solid #989898; 262 border: 1px solid #989898;
238} 263}
239 264
240select { 265select {
241 font-size: 12px; 266 font-size: 1rem;
242 border: 1px solid #989898; 267 border: 1px solid #989898;
243} 268}
244 269
245input[type=text]#page_title { 270input[type=text]#tag_list,
246 width: 690px; 271input[type=text]#node_staged_slug,
247 font-size: 14px; 272input#move_to_search_term {
248 padding-top: 6px;
249 padding-bottom: 4px;
250 padding-left: 5px;
251 padding-right: 5px;
252 font-weight: bold;
253}
254
255input[type=text]#tag_list {
256 padding: 5px;
257}
258
259input[type=text]#node_slug {
260 padding: 5px; 273 padding: 5px;
261} 274}
262 275
@@ -285,6 +298,24 @@ div#login_form input[type=text], div#login_form input[type=password] {
285 width: 150px; 298 width: 150px;
286} 299}
287 300
301
302@media(min-width:1016px) {
303input#tag_list,
304input#node_staged_slug,
305input#move_to_search_term {
306 width: 690px;
307}
308
309input[type=text]#page_title {
310 width: 690px;
311 font-size: 1rem;
312 padding-top: 6px;
313 padding-bottom: 4px;
314 padding-left: 5px;
315 padding-right: 5px;
316 font-weight: bold;
317}
318
288textarea#page_abstract { 319textarea#page_abstract {
289 width: 690px; 320 width: 690px;
290 height: 150px; 321 height: 150px;
@@ -300,6 +331,56 @@ textarea#page_abstract {
300 margin-left: -125px; 331 margin-left: -125px;
301} 332}
302 333
334}
335
336/* Mobile */
337@media(max-width:1015px) {
338input#tag_list,
339input#node_staged_slug,
340input#move_to_search_term {
341 box-sizing: border-box;
342 width: 100%;
343}
344
345#page_editor #content,
346#page_editor #metadata {
347 padding-right: 5px;
348}
349
350#page_editor textarea#page_body {
351 box-sizing: border-box;
352 width: 800px;
353 height: 50rem;
354}
355
356#page_editor textarea#page_abstract {
357 box-sizing: border-box;
358 height: 8rem;
359 width: 100%;
360}
361
362input[type=text]#page_title {
363 box-sizing: border-box;
364 width: 100%;
365 font-size: 2rem;
366 padding-top: 6px;
367 padding-bottom: 4px;
368 padding-left: 5px;
369 font-weight: bold;
370}
371
372input[type=text], textarea {
373 font-size: 1.5rem;
374}
375select {
376 font-size: 1.5rem;
377}
378
379#metadata ul#image_box {
380 width: 100% !important;
381}
382}
383
303#new_node { 384#new_node {
304 margin-left: -118px; 385 margin-left: -118px;
305} 386}
@@ -316,14 +397,38 @@ td {
316 padding-right: 10px; 397 padding-right: 10px;
317} 398}
318 399
319td.description { 400@media(min-width:1016px) {
320 width: 100px; 401div.node_description {
402 float: left;
403 width: 110px;
404 min-height: 2rem;
321 text-align: right; 405 text-align: right;
322 text-transform: lowercase; 406 text-transform: lowercase;
323 letter-spacing: 1px;
324 vertical-align: top; 407 vertical-align: top;
325} 408}
326 409
410div.node_content {
411 margin-left: 120px;
412 min-height: 2rem;
413 display: block;
414 margin-bottom: 1rem;
415}
416}
417@media(max-width:1015px) {
418div.node_description {
419 min-height: 2rem;
420 width: 30em;
421 text-transform: lowercase;
422 vertical-align: top;
423}
424
425div.node_content {
426 min-height: 2rem;
427 margin-bottom: 1rem;
428}
429
430}
431
327div#page_editor { 432div#page_editor {
328 margin-top: 0px; 433 margin-top: 0px;
329 margin-left: 10px; 434 margin-left: 10px;
@@ -401,6 +506,10 @@ table#content th.content {
401 506
402#menu_item_list { 507#menu_item_list {
403 border-collapse: collapse; 508 border-collapse: collapse;
509 padding: 5px 5px 5px 5px;
510 border: solid 5px lightgrey;
511 background-color: lightgrey;
512 border-radius: 5px;
404} 513}
405 514
406#menu_item_list tr:hover { 515#menu_item_list tr:hover {
@@ -413,16 +522,24 @@ table#content th.content {
413 522
414#menu_item_list td.menu_sort_handle div { 523#menu_item_list td.menu_sort_handle div {
415 background-color: #989898; 524 background-color: #989898;
416 height: 10px; 525 height: 26px;
417 width: 10px; 526 width: 26px;
527}
528
529#menu_item_list td.menu_sort_handle div:before {
530 content: "⇳";
531 font-size: 20px;
532 font-weight: bold;
533 text-align: center;
534 vertical-align: center;
418} 535}
419 536
420#menu_item_list td.menu_sort_handle div:hover { 537#menu_item_list td.menu_sort_handle div:hover {
421 cursor: move; 538 cursor: grab;
422} 539}
423 540
424#menu_item_list td.menu_item_title { 541#menu_item_list td.menu_item_title {
425 width: 100px; 542 width: 200px;
426} 543}
427 544
428.ui-state-highlight td{ 545.ui-state-highlight td{
@@ -430,12 +547,11 @@ table#content th.content {
430} 547}
431 548
432#metadata ul#image_box { 549#metadata ul#image_box {
550 box-sizing: border-box;
433 margin: 0; 551 margin: 0;
434 padding-left: 0; 552 padding: 10px 5px 10px 5px;
435 height: 100px; 553 height: 100px;
436 width: 690px; 554 width: 702px;
437 padding-top: 10px;
438 padding-bottom: 10px;
439 border: 1px solid #989898; 555 border: 1px solid #989898;
440} 556}
441 557
@@ -455,14 +571,6 @@ div#image_browser ul li {
455 list-style-type: none; 571 list-style-type: none;
456} 572}
457 573
458input#move_to_search_term, input#node_staged_slug {
459 width: 690px;
460}
461
462#tag_list {
463 width: 680px;
464}
465
466table.user_list td.user_login { 574table.user_list td.user_login {
467 padding-right: 30px; 575 padding-right: 30px;
468} 576}
diff --git a/public/stylesheets/ccc.css b/public/stylesheets/ccc.css
index c782b1f..c4530fa 100644
--- a/public/stylesheets/ccc.css
+++ b/public/stylesheets/ccc.css
@@ -1,34 +1,52 @@
1html {
2 height: 100%;
3 line-height: 1.6rem;
4}
5
1body { 6body {
2 margin: 0; 7 margin: 0;
3 padding: 0; 8 padding: 0;
4 text-align: center; 9 text-align: center;
5 font-family: Verdana, Helvetica, Arial, sans-serif; 10 font-family: Verdana, Helvetica, Arial, sans-serif;
6 background-color: Canvas; 11 background-color: Canvas;
12 color: color-mix(in srgb, CanvasText, #808080 25%);
7 hyphens: auto; 13 hyphens: auto;
8 color: color-mix(in srgb, CanvasText, #808080 30%);
9 color-scheme: light dark; 14 color-scheme: light dark;
10}
11 15
12body:has(#light-mode:checked) { 16 min-height: 100%;
13 color-scheme: light; 17 height: 100%;
14} 18}
15 19
16@media (prefers-color-scheme: light) { 20@media (prefers-color-scheme: light) {
17#light-mode-li, #light-mode, label[for=light-mode] { 21 body:has(#light-mode:checked) {
18 display: none; 22 color-scheme: dark;
19} 23 }
24 #light-mode + label[for=light-mode]:before { content: '🌙'; }
25 #light-mode:checked + label[for=light-mode]:before { content: '☀️'; }
26
27 /* The header images were set in the before times. Let them shine in dark
28 mode, too */
29 body:has(#light-mode:checked) #header img,
30 body:has(#light-mode:checked) div#left_column::before
31 {
32 filter: invert(50%);
33 }
20} 34}
21 35
22@media (prefers-color-scheme: dark) { 36@media (prefers-color-scheme: dark) {
23body:not(:has(#light-mode:checked)) #header img, 37 body:has(#light-mode:checked) {
24body:not(:has(#light-mode:checked)) div#left_column::before 38 color-scheme: light;
25{ 39 }
26 filter: invert(50%); 40 #light-mode + label[for=light-mode]:before { content: '☀️'; }
27} 41 #light-mode:checked + label[for=light-mode]:before { content: '🌙'; }
28}
29 42
30p { 43 /* The header images were set in the before times. Let them shine in dark
31 line-height: 1.5em; 44 mode, too */
45 body:not(:has(#light-mode:checked)) #header img,
46 body:not(:has(#light-mode:checked)) div#left_column::before
47 {
48 filter: invert(50%);
49 }
32} 50}
33 51
34img { 52img {
@@ -45,6 +63,10 @@ div#header img {
45 width: 909px; 63 width: 909px;
46 margin: 0 auto 0 auto; 64 margin: 0 auto 0 auto;
47 text-align: left; 65 text-align: left;
66 min-height: 100%;
67 }
68 .break-mobile {
69 display: block;
48 } 70 }
49} 71}
50 72
@@ -64,7 +86,8 @@ a {
64} 86}
65 87
66a:visited { 88a:visited {
67 color: #5b8ca7; 89 color: #D1791A;
90 text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
68} 91}
69 92
70a:hover { 93a:hover {
@@ -76,20 +99,25 @@ a:hover {
76h2 { 99h2 {
77 font-size: 1.5rem; 100 font-size: 1.5rem;
78 font-family: Helvetica, Arial, sans-serif; 101 font-family: Helvetica, Arial, sans-serif;
102 line-height: 1.75rem;
79} 103}
80 104
81div#center_column h2 a { 105div#center_column h2 a {
82 color: color-mix(in srgb, CanvasText, #808080 80%); 106 color: CanvasText;
83 text-decoration: none; 107 text-decoration: none;
84} 108}
85 109
86div#center_column h2 a:hover { 110div#center_column h2 a:hover {
87 color: color-mix(in srgb, CanvasText, #808080 10%); 111 color: color-mix(in srgb, CanvasText, #808080 50%);
88} 112}
89 113
90div#center_column h2.headline { 114div#center_column h2.headline {
91 margin-top: 10px; 115 margin-top: 10px;
116}
117
118div#center_column .article_partial h2.headline {
92 padding-top: 30px; 119 padding-top: 30px;
120 margin-bottom: 0.3rem;
93 border-top: 2px solid #cccccc; 121 border-top: 2px solid #cccccc;
94} 122}
95 123
@@ -105,11 +133,10 @@ h3 {
105 133
106h4 { 134h4 {
107 font-size: 1.0rem; 135 font-size: 1.0rem;
108 text-decoration: bold; 136 text-decoration: none;
109} 137}
110 138
111#left_column { 139#left_column {
112 font-size: .8em;
113 line-height: 1.5em; 140 line-height: 1.5em;
114} 141}
115 142
@@ -123,20 +150,19 @@ div.main_navigation ul {
123 text-align: left; 150 text-align: left;
124} 151}
125 152
126div.main_navigation li {
127 list-style-type: none;
128 display: inline-block;
129 line-height: 1.75em;
130}
131 153
132div.main_navigation li::after { 154@media(max-width:1016px) {
133 content: '-'; 155 div.main_navigation li:not(:first-child):before {
134 color: #aeadad; 156 content: '•';
135 margin-left: .3em; 157 margin-left: .3rem;
136} 158 margin-right: .6rem;
159 }
137 160
138div.main_navigation li:last-child::after { 161 div.main_navigation li {
139 content: none; 162 list-style-type: none;
163 display: inline-block;
164 line-height: .75rem;
165 }
140} 166}
141 167
142@media(min-width:1016px) { 168@media(min-width:1016px) {
@@ -146,21 +172,21 @@ div.main_navigation li:last-child::after {
146 } 172 }
147 173
148 div.main_navigation li { 174 div.main_navigation li {
149 display: block; 175 list-style-type: none;
150 line-height: 1.45em; 176 line-height: 1.45em;
151 } 177 }
152
153 div.main_navigation li::after {
154 content: none;
155 }
156} 178}
157 179
158div.main_navigation a { 180div.main_navigation a {
159 text-decoration: none; 181 text-decoration: none;
160} 182}
161 183
162div.main_navigation a.inactive:hover { 184div.main_navigation a.inactive:hover, div#left_column span.inactive:hover {
163 color: #F8921E; 185 color: color-mix(in srgb, CanvasText, #808080 50%);
186}
187
188div.main_navigation a.active:before {
189 content: "▸";
164} 190}
165 191
166div.main_navigation a.active { 192div.main_navigation a.active {
@@ -168,8 +194,8 @@ div.main_navigation a.active {
168 text-decoration: none; 194 text-decoration: none;
169} 195}
170 196
171div.main_navigation a.inactive { 197div.main_navigation a.inactive, div.main_navigation span.inactive, div#left_column span.inactive {
172 color: #aeadad; 198 color: color-mix(in srgb, CanvasText, #808080 25%);
173} 199}
174 200
175/*------------------calendar-featured-tags-------------------*/ 201/*------------------calendar-featured-tags-------------------*/
@@ -185,10 +211,9 @@ div#frontpage_calendar {
185 } 211 }
186} 212}
187 213
188div#frontpage_calendar h2, div#tags h2, div#featured_articles h2 { 214div#frontpage_calendar h2, div#tags h2, div#featured_articles h2, div.main_navigation h2 {
189 color: #aeadad; 215 border-top: 2px solid;
190 border-top: 2px solid #aeadad; 216 border-bottom: 2px solid;
191 border-bottom: 2px solid #aeadad;
192 font-size: 1.1em; 217 font-size: 1.1em;
193 padding-top: 2px; 218 padding-top: 2px;
194 padding-bottom: 2px; 219 padding-bottom: 2px;
@@ -204,9 +229,22 @@ div#frontpage_calendar h2 {
204 margin-top: 0; 229 margin-top: 0;
205} 230}
206 231
232@media(max-width:1016px) {
233 div#tags li {
234 list-style-type: none;
235 display: inline-block;
236 }
237
238 div#tags li:not(:first-child):before {
239 content: '•';
240 margin-left: .3em;
241 margin-right: .6em;
242 }
243}
244
207@media(min-width:1016px) { 245@media(min-width:1016px) {
208 div#frontpage_calendar h2, div#tags h2, div#featured_articles h2 { 246 div#frontpage_calendar h2, div#tags h2, div#featured_articles h2 {
209 font-size: 16px; 247 font-size: 1rem;
210 } 248 }
211 249
212 div#frontpage_calendar h2 { 250 div#frontpage_calendar h2 {
@@ -214,20 +252,15 @@ div#frontpage_calendar h2 {
214 border-top: 2px solid #aeadad; 252 border-top: 2px solid #aeadad;
215 padding: 2px 0; 253 padding: 2px 0;
216 } 254 }
255
217} 256}
218 257
219div#frontpage_calendar ul, div#tags ul, div#featured_articles ul { 258div#frontpage_calendar ul, div#tags ul, div#featured_articles ul {
220 padding: 0px; 259 padding: 0px;
221 font-size: 0.8em; 260 font-size: 1rem;
222 line-height: 1.5em; 261 line-height: 1.5em;
223} 262}
224 263
225@media(min-width:1016px) {
226 div#tags ul {
227 font-size: 0.8rem;
228 }
229}
230
231div#featured_articles #ds_icon img { 264div#featured_articles #ds_icon img {
232 padding-top: 10px; 265 padding-top: 10px;
233} 266}
@@ -246,22 +279,39 @@ div#frontpage_calendar li, div#tags li, div#featured_articles li {
246 279
247div#frontpage_calendar li a, div#tags li a, div#featured_articles li a { 280div#frontpage_calendar li a, div#tags li a, div#featured_articles li a {
248 text-decoration: none; 281 text-decoration: none;
249 color: #535353; 282 color: color-mix(in srgb, CanvasText, #808080 25%);
250} 283}
251 284
252div#frontpage_calendar li a:hover, 285div#frontpage_calendar li a:hover,
253div#tags li a:hover, 286div#tags li a:hover,
254div#featured_articles li a:hover { 287div#featured_articles li a:hover {
255 text-decoration: none; 288 text-decoration: none;
256 color: #ff9600; 289 color: color-mix(in srgb, CanvasText, #808080 50%);
290}
291
292/* We don't want the only colourful thing on the site to be pointing
293 * somewhere else */
294div#featured_articles img {
295 filter: grayscale(1);
296}
297
298dt {
299 font-weight: bold;
300 margin-bottom: 1em;
301}
302
303dd {
304 margin-bottom: 1em;
257} 305}
258 306
259/*--------------------------------------------------------------*/ 307/*--------------------------------------------------------------*/
260 308
261div.author_and_date { 309div.author_and_date {
262 font-style: italic; 310 font-style: italic;
263 padding-left: 2em;
264 font-family: Georgia; 311 font-family: Georgia;
312 color: color-mix(in srgb, CanvasText, #808080);
313 padding-top: .2rem;
314 padding-bottom: .8rem;
265} 315}
266 316
267@media(min-width:1016px) { 317@media(min-width:1016px) {
@@ -281,10 +331,10 @@ div.author_and_date {
281 div#left_column { 331 div#left_column {
282 position: absolute; 332 position: absolute;
283 left: 0px; 333 left: 0px;
284 width: 115px; 334 width: 135px;
285 min-height: 100px; 335 min-height: 100px;
286 text-align: right; 336 text-align: right;
287 padding-right: 70px; 337 padding-right: 50px;
288 } 338 }
289 339
290 div#left_column > a { 340 div#left_column > a {
@@ -292,19 +342,85 @@ div.author_and_date {
292 } 342 }
293} 343}
294 344
345.menu-checkbox {
346 display: none;
347}
348
349.burger-menu {
350 display: none;
351 cursor: pointer;
352}
353
354#burger-div {
355 position: absolute;
356 right: 54px;
357}
358
359/* Mobile styles */
360@media (max-width: 1016px) {
361 .burger-menu {
362 position: absolute;
363 display: flex;
364 flex-direction: column;
365 transition: transform 0.3s ease, opacity 0.3s ease;
366 }
367
368 .burger-menu span {
369 display: inline-flex;
370 width: 26px;
371 height: 4px;
372 background: color-mix(in srgb, CanvasText, #808080 25%);
373 border-radius: 2px;
374 margin: 3px 0;
375 transition: max-height 0.5s ease-in-out, opacity 0.5s ease-in-out, transform 0.5s ease-in-out;
376 }
377
378 #left_column .main_navigation {
379 width: 100%;
380 position: relative;
381 }
382
383 #toolbox ~ #left_column .main_navigation ul {
384 transition: max-height 0.2s ease-in-out, transform 0.4s ease-in-out, opacity 0.4s ease;
385 overflow: hidden;
386 text-align: center;
387 }
388
389 #toolbox ~ #left_column .main_navigation:first-of-type ul {
390 transform: translateY(-200px);
391 max-height: 0;
392 opacity: 0;
393 z-index: -10;
394 }
395
396 /* Show menu when checkbox is checked */
397 #toolbox:has(.menu-checkbox:checked) ~ #left_column .main_navigation ul {
398 max-height: 400px;
399 opacity: 1;
400 transform: translateY(0);
401 }
402
403 .menu-checkbox:checked + .burger-menu span:nth-child(1) { transform: translateY(10px) rotate(45deg); }
404 .menu-checkbox:checked + .burger-menu span:nth-child(2) { opacity: 0; }
405 .menu-checkbox:checked + .burger-menu span:nth-child(3) { transform: translateY(-10px) rotate(-45deg); }
406}
295 407
296div#center_column { 408div#center_column {
297 padding-left: 15px;
298 padding-right: 15px;
299 padding-bottom: 40px; 409 padding-bottom: 40px;
300} 410}
301 411
412@media(max-width: 1016px) {
413div#center_column {
414 padding: 0 15px 40px 15px;
415}
416}
417
302@media(min-width: 1016px) { 418@media(min-width: 1016px) {
303 div#center_column { 419 div#center_column {
304 position: absolute; 420 position: absolute;
305 background-color: Canvas; 421 background-color: Canvas;
306 left: 200px; 422 left: 200px;
307 width: 460px; 423 width: 490px;
308 } 424 }
309} 425}
310 426
@@ -312,8 +428,8 @@ div#center_column {
312 div#right_column { 428 div#right_column {
313 position: absolute; 429 position: absolute;
314 background-color: Canvas; 430 background-color: Canvas;
315 padding-left: 70px; 431 padding-left: 55px;
316 left: 675px; 432 left: 690px;
317 width: 155px; 433 width: 155px;
318 height: 100px; 434 height: 100px;
319 } 435 }
@@ -332,51 +448,48 @@ div.article_partial {
332 448
333 449
334div.article_partial p.excerpt { 450div.article_partial p.excerpt {
335 color: color-mix(in srgb, CanvasText, #808080 50%); 451 color: CanvasText;
336} 452}
337 453
338/* Search bar */ 454/* Search bar */
339#search form table {
340 display: inline-table;
341}
342
343@media(min-width:1016px) { 455@media(min-width:1016px) {
344 #search form table {
345 display: table;
346 }
347
348 div#search { 456 div#search {
349 position: absolute; 457 position: absolute;
350 top: 145px; 458 top: 145px;
351 left: 676px; 459 left: 676px;
352 height: 20px; 460 height: 25px;
353 vertical-align: top; 461 vertical-align: top;
354 } 462 }
355} 463}
356 464
357div#search input[type=button] { 465@media(max-width:1016px) {
358 display: block; 466 div#search {
359 height: 20px; 467 position: absolute;
468 left: 25px;
469 height: 25px;
470 }
360} 471}
361 472
473div#search input {
474 color: CanvasText !important;
475}
476div#search input[type=search],
362div#search input[type=text] { 477div#search input[type=text] {
363 display: block; 478 display: block;
364 padding: 0px; 479 padding: 2px;
365 margin: 0px; 480 margin: 0px;
366 height: 20px; 481 height: 25px;
367 width: 132px; 482 width: 132px;
368 line-height: 20px; 483 line-height: 20px;
369 border: solid Canvas 1px; 484 border: solid #808080 1px;
485 background-color: Canvas;
370 border-radius: 5px; 486 border-radius: 5px;
371 background-image: url(/images/search_field.png);
372 background-repeat:no-repeat;
373 margin-right: 5px; 487 margin-right: 5px;
374 text-indent: 0.5rem; 488 text-indent: 0.5rem;
375 background-position: top;
376 color: #000;
377} 489}
378 490
379/* Header */ 491/* Header */
492#header img,
380#header > a { 493#header > a {
381 display: block; 494 display: block;
382 line-height: 0; 495 line-height: 0;
@@ -384,37 +497,35 @@ div#search input[type=text] {
384 497
385/* Main section */ 498/* Main section */
386.article, .article_partial { 499.article, .article_partial {
387 font-size: .9rem;
388 text-align: left; 500 text-align: left;
389} 501}
390 502
391/*
392@media(min-width:1016px) {
393 .article, .article_partial {
394 font-size: 11px;
395 }
396}
397*/
398
399h1, h2, h3 { 503h1, h2, h3 {
400 word-wrap: anywhere; 504 word-wrap: anywhere;
401 hyphens:auto; 505 hyphens:auto;
402} 506}
403 507
404.pagination { 508.pagination {
405 margin-bottom: .5em; 509 margin-bottom: .5rem;
406} 510}
407 511
408li { 512li {
409 line-height: 1.5em; 513 line-height: 1.5rem;
410 margin-block-start: 1em; 514 margin-block-start: 1rem;
411 margin-block-end: 1em; 515 margin-block-end: 1rem;
516}
517
518#tags ul li {
519 margin-block-start: 0.5rem;
520 margin-block-end: 0.5rem;
412} 521}
413 522
414/* Footer */ 523/* Footer */
415#footer { 524#footer {
416 border-bottom: 2px solid #aeadad; 525 border-bottom: 2px solid #aeadad;
417 border-top: 2px solid #aeadad; 526 border-top: 2px solid #aeadad;
527 bottom: 0;
528 color: CanvasText;
418} 529}
419 530
420#footer > br { 531#footer > br {
@@ -422,5 +533,63 @@ li {
422} 533}
423 534
424#footer p { 535#footer p {
425 margin: .5em auto; 536 margin: .5rem auto;
426} 537}
538
539#footer a {
540 margin-left: 1rem;
541 margin-right: 1rem;
542 color: CanvasText;
543}
544
545@media(max-width:1016px) {
546#toolbox {
547 display: relative;
548 height: 30px;
549}
550}
551
552/* Light and dark mode button magic */
553@media(max-width:1016px) {
554 div#light-mode-div {
555 position: absolute;
556 left: 170px;
557 }
558}
559
560@media(min-width:1016px) {
561 div#light-mode-div {
562 position: absolute;
563 top: 145px;
564 left: 816px;
565 }
566}
567input#light-mode[type="checkbox"] {
568 display: none;
569}
570
571label[for=light-mode] {
572 font-size: 25px;
573 user-select: none;
574 cursor: pointer;
575 filter: grayscale(1) contrast(10%);
576}
577
578.hide-me {
579 display: none;
580}
581
582/* Temporary glowing style for easterhegg 22 */
583#eh22_icon img {
584 animation: animate 3s linear infinite;
585}
586
587@keyframes animate {
588 from {
589 filter: sepia(100%) hue-rotate(0deg);
590 }
591 to {
592 filter: sepia(100%) hue-rotate(360deg);
593 }
594}
595
diff --git a/test/functional/nodes_controller_test.rb b/test/functional/nodes_controller_test.rb
index 113697a..f5a16ee 100644
--- a/test/functional/nodes_controller_test.rb
+++ b/test/functional/nodes_controller_test.rb
@@ -347,4 +347,40 @@ class NodesControllerTest < ActionController::TestCase
347 assert_equal "quentin", node.draft.user.login 347 assert_equal "quentin", node.draft.user.login
348 assert_equal "aaron", node.draft.editor.login 348 assert_equal "aaron", node.draft.editor.login
349 end 349 end
350
351 test "destroy a published node" do
352 node = create_node_with_published_page
353 node.destroy
354
355 login_as :quentin
356 get :index
357 end
358
359 test "no dangling pages remain after node removal" do
360 node = create_node_with_published_page
361 page_id = node.pages.first.id
362 node.destroy
363
364 assert_raises(ActiveRecord::RecordNotFound) do
365 assert Page.find page_id
366 end
367 end
368
369 test "can remove a node with an event" do
370 node = create_node_with_published_page
371 Event.create!(
372 :start_time => "2009-01-01T15:23:42".to_time,
373 :end_time => "2009-01-01T20:05:23".to_time,
374 :url => "http://events.ccc.de/congress/2082",
375 :latitude => 52.525308,
376 :longitude => 13.378944,
377 :allday => true,
378 :node_id => node.id
379 )
380 node.destroy
381
382 login_as :quentin
383 get :index
384 end
385
350end 386end
diff --git a/vendor/plugins/paperclip/lib/paperclip/geometry.rb b/vendor/plugins/paperclip/lib/paperclip/geometry.rb
index 7fbe038..37ba706 100644
--- a/vendor/plugins/paperclip/lib/paperclip/geometry.rb
+++ b/vendor/plugins/paperclip/lib/paperclip/geometry.rb
@@ -20,6 +20,7 @@ module Paperclip
20 rescue PaperclipCommandLineError 20 rescue PaperclipCommandLineError
21 "" 21 ""
22 end 22 end
23 puts(geometry)
23 parse(geometry) || 24 parse(geometry) ||
24 raise(NotIdentifiedByImageMagickError.new("#{file} is not recognized by the 'identify' command.")) 25 raise(NotIdentifiedByImageMagickError.new("#{file} is not recognized by the 'identify' command."))
25 end 26 end