almanack 0.0.1.alpha3 → 1.0.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +55 -13
- data/almanac.gemspec +2 -1
- data/bin/almanack +3 -0
- data/example.ru +18 -14
- data/lib/almanack.rb +16 -13
- data/lib/almanack/calendar.rb +35 -3
- data/lib/almanack/cli.rb +131 -0
- data/lib/almanack/configuration.rb +20 -4
- data/lib/almanack/event.rb +26 -1
- data/lib/almanack/event_source/ical_feed.rb +62 -0
- data/lib/almanack/event_source/meetup_group.rb +98 -0
- data/lib/almanack/event_source/static.rb +23 -0
- data/lib/almanack/server.rb +75 -4
- data/lib/almanack/themes/legacy/stylesheets/calendar.scss +168 -0
- data/lib/almanack/themes/legacy/views/error.erb +13 -0
- data/lib/almanack/themes/legacy/views/events.erb +4 -2
- data/lib/almanack/themes/legacy/views/layout.erb +9 -6
- data/lib/almanack/themes/starter/javascripts/calendar.js +5 -0
- data/lib/almanack/themes/starter/stylesheets/calendar.scss +27 -0
- data/lib/almanack/themes/starter/views/error.erb +13 -0
- data/lib/almanack/themes/starter/views/events.erb +31 -0
- data/lib/almanack/themes/starter/views/layout.erb +32 -0
- data/lib/almanack/version.rb +4 -1
- data/spec/almanack_spec.rb +8 -0
- data/spec/calendar_spec.rb +29 -25
- data/spec/configuration_spec.rb +19 -3
- data/spec/{ical_feed_spec.rb → event_source/ical_feed_spec.rb} +4 -4
- data/spec/{meetup_group_spec.rb → event_source/meetup_group_spec.rb} +4 -4
- data/spec/event_source/static_spec.rb +23 -0
- data/spec/event_spec.rb +24 -4
- data/spec/features/calendar_feature_spec.rb +7 -5
- data/spec/features/subscription_feature_spec.rb +60 -0
- data/spec/spec_helper.rb +2 -1
- data/spec/support/server_support.rb +2 -1
- data/spec/support/time_comparison_matchers.rb +14 -0
- data/templates/gitignore +2 -0
- data/templates/new/Gemfile +3 -0
- data/templates/new/config.ru.tt +24 -0
- metadata +45 -13
- data/lib/almanack/ical_feed.rb +0 -60
- data/lib/almanack/meetup_group.rb +0 -96
- data/lib/almanack/simple_event_collection.rb +0 -11
- data/lib/almanack/themes/legacy/views/stylesheets/legacy.css.sass +0 -119
- data/spec/simple_event_collection_spec.rb +0 -23
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Consolidated iCal feed", :feature do
|
4
|
+
let(:now) { Time.now }
|
5
|
+
let(:parsed_feed) { RiCal.parse_string(Almanack.calendar.ical_feed) }
|
6
|
+
let(:parsed_cal) { parsed_feed.first }
|
7
|
+
let(:parsed_events) { parsed_cal.events }
|
8
|
+
|
9
|
+
before do
|
10
|
+
Timecop.freeze(now)
|
11
|
+
|
12
|
+
Almanack.reset!
|
13
|
+
|
14
|
+
Almanack.config.add_events [
|
15
|
+
{ title: "Basic", start_date: now },
|
16
|
+
{ title: "Almost a year away", start_date: now + 364 * 24 * 60 * 60 },
|
17
|
+
{ title: "Over a year away", start_date: now + 366 * 24 * 60 * 60 },
|
18
|
+
{
|
19
|
+
title: "Complex",
|
20
|
+
start_date: now,
|
21
|
+
end_date: now + 30 * 24 * 60 * 60,
|
22
|
+
description: "Body",
|
23
|
+
location: "CA"
|
24
|
+
}
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
after { Timecop.return }
|
29
|
+
|
30
|
+
it "should contain one calendar entity" do
|
31
|
+
expect(parsed_feed.length).to eq(1)
|
32
|
+
expect(parsed_feed.first).to be_an_instance_of(RiCal::Component::Calendar)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "contains a year's worth of events" do
|
36
|
+
expect(parsed_events.length).to eq(3)
|
37
|
+
expect(parsed_events.map(&:summary)).to_not include("Over a year away")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "contains all available event information" do
|
41
|
+
complex_event = parsed_events.find { |e| e.summary == 'Complex' }
|
42
|
+
expect(complex_event.dtstart).to eq_time(now)
|
43
|
+
expect(complex_event.dtend).to eq_time(now + 30 * 24 * 60 * 60)
|
44
|
+
expect(complex_event.description).to eq('Body')
|
45
|
+
expect(complex_event.location).to eq('CA')
|
46
|
+
end
|
47
|
+
|
48
|
+
it "treats missing end dates as three hours from the start date" do
|
49
|
+
three_hours_from_now = now + 3 * 60 * 60
|
50
|
+
basic_event = parsed_events.find { |e| e.summary == 'Basic' }
|
51
|
+
expect(basic_event.dtend).to eq_time(three_hours_from_now)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "can be accessed from the server" do
|
55
|
+
allow(Almanack.calendar).to receive(:ical_feed) { "feed" }
|
56
|
+
get "/feed.ics"
|
57
|
+
expect(last_response.body).to eq("feed")
|
58
|
+
expect(last_response.headers["Content-Type"]).to include("text/calendar")
|
59
|
+
end
|
60
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -13,10 +13,11 @@ Dir[File.expand_path('../support/*.rb', __FILE__)].each { |file| require file }
|
|
13
13
|
RSpec.configure do |config|
|
14
14
|
config.include ServerSupport, :feature
|
15
15
|
config.include EventMatchers
|
16
|
+
config.include TimeComparisonMatchers
|
16
17
|
end
|
17
18
|
|
18
19
|
VCR.configure do |config|
|
19
20
|
config.cassette_library_dir = File.expand_path('../fixtures/responses', __FILE__)
|
20
21
|
config.ignore_hosts 'codeclimate.com'
|
21
22
|
config.hook_into :webmock
|
22
|
-
end
|
23
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module TimeComparisonMatchers
|
2
|
+
extend RSpec::Matchers::DSL
|
3
|
+
|
4
|
+
matcher :eq_time do |expected_time|
|
5
|
+
match do |actual_time|
|
6
|
+
actual_time.to_time.to_i == expected_time.to_time.to_i
|
7
|
+
end
|
8
|
+
|
9
|
+
failure_message do |actual_time|
|
10
|
+
"expected #{actual_time.to_time} to be equal in time to #{expected_time.to_time}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
data/templates/gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'almanack/server'
|
2
|
+
|
3
|
+
Almanack.config do |c|
|
4
|
+
c.title = "My Calendar"
|
5
|
+
c.theme = "<%= theme_name %>" # available: <%= available_themes.join(', ') %>
|
6
|
+
|
7
|
+
# Your group's URL name is what you'd find at www.meetup.com/Your-Group-URL-Name/
|
8
|
+
# You can get a Meetup API key from https://secure.meetup.com/meetup_api/key
|
9
|
+
# c.add_meetup_group group_urlname: 'Christchurch-Ruby-Group', key: 'mysecretkey'
|
10
|
+
|
11
|
+
# For a Google Calendar, find the "iCal" link under your Calendar's settings
|
12
|
+
# c.add_ical_feed 'https://example.com/basic.ics'
|
13
|
+
|
14
|
+
# Static events
|
15
|
+
c.add_events [
|
16
|
+
{
|
17
|
+
title: "Edit my calendar's settings",
|
18
|
+
description: "Edit the configuration at #{__FILE__}",
|
19
|
+
start_date: Time.now + 30 * 60
|
20
|
+
}
|
21
|
+
]
|
22
|
+
end
|
23
|
+
|
24
|
+
run Almanack::Server
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: almanack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 1.0.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pete Nicholls
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: thor
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: bundler
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -209,7 +223,8 @@ dependencies:
|
|
209
223
|
description:
|
210
224
|
email:
|
211
225
|
- pete@metanation.com
|
212
|
-
executables:
|
226
|
+
executables:
|
227
|
+
- almanack
|
213
228
|
extensions: []
|
214
229
|
extra_rdoc_files: []
|
215
230
|
files:
|
@@ -220,31 +235,45 @@ files:
|
|
220
235
|
- README.md
|
221
236
|
- Rakefile
|
222
237
|
- almanac.gemspec
|
238
|
+
- bin/almanack
|
223
239
|
- example.ru
|
224
240
|
- lib/almanack.rb
|
225
241
|
- lib/almanack/calendar.rb
|
242
|
+
- lib/almanack/cli.rb
|
226
243
|
- lib/almanack/configuration.rb
|
227
244
|
- lib/almanack/event.rb
|
228
|
-
- lib/almanack/ical_feed.rb
|
229
|
-
- lib/almanack/meetup_group.rb
|
245
|
+
- lib/almanack/event_source/ical_feed.rb
|
246
|
+
- lib/almanack/event_source/meetup_group.rb
|
247
|
+
- lib/almanack/event_source/static.rb
|
230
248
|
- lib/almanack/server.rb
|
231
|
-
- lib/almanack/
|
249
|
+
- lib/almanack/themes/legacy/stylesheets/calendar.scss
|
250
|
+
- lib/almanack/themes/legacy/views/error.erb
|
232
251
|
- lib/almanack/themes/legacy/views/events.erb
|
233
252
|
- lib/almanack/themes/legacy/views/layout.erb
|
234
|
-
- lib/almanack/themes/
|
253
|
+
- lib/almanack/themes/starter/javascripts/calendar.js
|
254
|
+
- lib/almanack/themes/starter/stylesheets/calendar.scss
|
255
|
+
- lib/almanack/themes/starter/views/error.erb
|
256
|
+
- lib/almanack/themes/starter/views/events.erb
|
257
|
+
- lib/almanack/themes/starter/views/layout.erb
|
235
258
|
- lib/almanack/version.rb
|
259
|
+
- spec/almanack_spec.rb
|
236
260
|
- spec/calendar_spec.rb
|
237
261
|
- spec/configuration_spec.rb
|
262
|
+
- spec/event_source/ical_feed_spec.rb
|
263
|
+
- spec/event_source/meetup_group_spec.rb
|
264
|
+
- spec/event_source/static_spec.rb
|
238
265
|
- spec/event_spec.rb
|
239
266
|
- spec/features/calendar_feature_spec.rb
|
267
|
+
- spec/features/subscription_feature_spec.rb
|
240
268
|
- spec/fixtures/responses/google_calendar.yml
|
241
269
|
- spec/fixtures/responses/meetup.yml
|
242
|
-
- spec/ical_feed_spec.rb
|
243
|
-
- spec/meetup_group_spec.rb
|
244
|
-
- spec/simple_event_collection_spec.rb
|
245
270
|
- spec/spec_helper.rb
|
246
271
|
- spec/support/event_matchers.rb
|
247
272
|
- spec/support/server_support.rb
|
273
|
+
- spec/support/time_comparison_matchers.rb
|
274
|
+
- templates/gitignore
|
275
|
+
- templates/new/Gemfile
|
276
|
+
- templates/new/config.ru.tt
|
248
277
|
homepage: https://github.com/Aupajo/sinatra-gcal
|
249
278
|
licenses:
|
250
279
|
- MIT
|
@@ -270,15 +299,18 @@ signing_key:
|
|
270
299
|
specification_version: 4
|
271
300
|
summary: Combined events calendar for Google Calendar, iCal, Meetup.com and friends.
|
272
301
|
test_files:
|
302
|
+
- spec/almanack_spec.rb
|
273
303
|
- spec/calendar_spec.rb
|
274
304
|
- spec/configuration_spec.rb
|
305
|
+
- spec/event_source/ical_feed_spec.rb
|
306
|
+
- spec/event_source/meetup_group_spec.rb
|
307
|
+
- spec/event_source/static_spec.rb
|
275
308
|
- spec/event_spec.rb
|
276
309
|
- spec/features/calendar_feature_spec.rb
|
310
|
+
- spec/features/subscription_feature_spec.rb
|
277
311
|
- spec/fixtures/responses/google_calendar.yml
|
278
312
|
- spec/fixtures/responses/meetup.yml
|
279
|
-
- spec/ical_feed_spec.rb
|
280
|
-
- spec/meetup_group_spec.rb
|
281
|
-
- spec/simple_event_collection_spec.rb
|
282
313
|
- spec/spec_helper.rb
|
283
314
|
- spec/support/event_matchers.rb
|
284
315
|
- spec/support/server_support.rb
|
316
|
+
- spec/support/time_comparison_matchers.rb
|
data/lib/almanack/ical_feed.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
require 'uri'
|
3
|
-
require 'ri_cal'
|
4
|
-
|
5
|
-
module Almanack
|
6
|
-
class IcalFeed
|
7
|
-
def initialize(url)
|
8
|
-
@url = url
|
9
|
-
end
|
10
|
-
|
11
|
-
def events_between(date_range)
|
12
|
-
occurrences_between(date_range).map do |occurrence|
|
13
|
-
event_from(occurrence)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def each_ical_event(&block)
|
20
|
-
entities.each do |entity|
|
21
|
-
entity.events.each(&block) if entity.respond_to?(:events)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def occurrences_between(date_range)
|
26
|
-
to_date = date_range.max
|
27
|
-
from_date = date_range.min
|
28
|
-
|
29
|
-
occurrences = []
|
30
|
-
|
31
|
-
each_ical_event do |ical_event|
|
32
|
-
ical_event.occurrences(starting: from_date, before: to_date).each do |occurrence|
|
33
|
-
occurrences << occurrence
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
occurrences
|
38
|
-
end
|
39
|
-
|
40
|
-
def event_from(occurrence)
|
41
|
-
Event.new(
|
42
|
-
title: occurrence.summary,
|
43
|
-
start_date: occurrence.dtstart,
|
44
|
-
end_date: occurrence.dtend,
|
45
|
-
description: occurrence.description,
|
46
|
-
location: occurrence.location
|
47
|
-
)
|
48
|
-
end
|
49
|
-
|
50
|
-
def entities
|
51
|
-
RiCal.parse_string(body)
|
52
|
-
end
|
53
|
-
|
54
|
-
def body
|
55
|
-
uri = URI(@url)
|
56
|
-
Net::HTTP.get(uri)
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
require 'json'
|
3
|
-
require 'addressable/uri'
|
4
|
-
|
5
|
-
module Almanack
|
6
|
-
class MeetupGroup
|
7
|
-
def initialize(options = {})
|
8
|
-
@request_options = options
|
9
|
-
end
|
10
|
-
|
11
|
-
def events_between(date_range)
|
12
|
-
events.select do |event|
|
13
|
-
event.start_date >= date_range.min && event.start_date <= date_range.max
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def events
|
20
|
-
request = MeetupAPIRequest.new(@request_options)
|
21
|
-
request.results.map { |result| event_from(result) }
|
22
|
-
end
|
23
|
-
|
24
|
-
def event_from(result)
|
25
|
-
# 3 hours, as recommended by Meetup.com if duration isn't present
|
26
|
-
default_duration_in_ms = 3 * 60 * 60 * 1000
|
27
|
-
|
28
|
-
event_name = [result['group']['name'], result['name']].compact.join(': ')
|
29
|
-
start_time = Time.at(result['time'] / 1000)
|
30
|
-
duration_in_secs = (result['duration'] || default_duration_in_ms) / 1000
|
31
|
-
end_time = start_time + duration_in_secs
|
32
|
-
|
33
|
-
Event.new(
|
34
|
-
title: event_name,
|
35
|
-
start_date: start_time.to_datetime,
|
36
|
-
end_date: end_time.to_datetime,
|
37
|
-
description: result['description'],
|
38
|
-
location: location_from_venue(result['venue']),
|
39
|
-
url: result['event_url']
|
40
|
-
)
|
41
|
-
end
|
42
|
-
|
43
|
-
def location_from_venue(venue)
|
44
|
-
%w{ name address_1 address_2 address_3 city state country }.map do |attr|
|
45
|
-
venue[attr]
|
46
|
-
end.compact.join(', ')
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
class MeetupAPIError < StandardError
|
51
|
-
end
|
52
|
-
|
53
|
-
class MeetupAPIException < Exception
|
54
|
-
end
|
55
|
-
|
56
|
-
class MeetupAPIRequest
|
57
|
-
REQUIRED_OPTIONS = [:group_domain, :group_urlname, :group_id]
|
58
|
-
|
59
|
-
attr_accessor :options
|
60
|
-
|
61
|
-
def initialize(options = {})
|
62
|
-
@options = options
|
63
|
-
end
|
64
|
-
|
65
|
-
def results
|
66
|
-
response['results']
|
67
|
-
end
|
68
|
-
|
69
|
-
def uri
|
70
|
-
if !options.has_key?(:key)
|
71
|
-
raise MeetupAPIException, 'Cannot form valid URI, missing :key option'
|
72
|
-
end
|
73
|
-
|
74
|
-
if (options.keys & REQUIRED_OPTIONS).empty?
|
75
|
-
raise MeetupAPIException, "Cannot form valid URI, missing one of: #{REQUIRED_OPTIONS}"
|
76
|
-
end
|
77
|
-
|
78
|
-
endpoint = "https://api.meetup.com/2/events"
|
79
|
-
|
80
|
-
Addressable::URI.parse(endpoint).tap do |uri|
|
81
|
-
uri.query_values = options
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def response
|
86
|
-
json = Net::HTTP.get(uri)
|
87
|
-
data = JSON.parse(json)
|
88
|
-
|
89
|
-
if data['problem']
|
90
|
-
raise MeetupAPIError, data['problem']
|
91
|
-
end
|
92
|
-
|
93
|
-
data
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
@@ -1,119 +0,0 @@
|
|
1
|
-
=border-radius($size)
|
2
|
-
border-radius: $size
|
3
|
-
-webkit-border-radius: $size
|
4
|
-
-moz-border-radius: $size
|
5
|
-
|
6
|
-
=box-shadow($x, $y, $size, $colour)
|
7
|
-
-webkit-box-shadow: $x $y $size $colour
|
8
|
-
-moz-box-shadow: $x $y $size $colour
|
9
|
-
|
10
|
-
body
|
11
|
-
background-color: #e3e3e3
|
12
|
-
color: #595959
|
13
|
-
font: 12pt / 1.6em "Helvetica Neue", Helvetica, sans-serif
|
14
|
-
margin: 2em auto
|
15
|
-
width: 600px
|
16
|
-
|
17
|
-
a
|
18
|
-
text-decoration: none
|
19
|
-
&:link, &:visited
|
20
|
-
color: #2960AA
|
21
|
-
|
22
|
-
em
|
23
|
-
font-style: italic
|
24
|
-
|
25
|
-
strong
|
26
|
-
font-weight: bold
|
27
|
-
|
28
|
-
.event
|
29
|
-
background-color: #efefef
|
30
|
-
background: -webkit-gradient(linear, left top, left bottom, from(#f9f9f9), to(#efefef))
|
31
|
-
background: -moz-linear-gradient(top, #f9f9f9, #efefef)
|
32
|
-
border-top: 1px solid white
|
33
|
-
+border-radius(4px)
|
34
|
-
overflow: hidden
|
35
|
-
padding: 20px
|
36
|
-
margin-bottom: 1em
|
37
|
-
+box-shadow(0, 1px, 3px, rgba(0, 0, 0, 0.3))
|
38
|
-
&.today
|
39
|
-
background-color: #ebe4de
|
40
|
-
background: -webkit-gradient(linear, left top, left bottom, from(#f3ebe3), to(#e9d6c1))
|
41
|
-
.details
|
42
|
-
float: right
|
43
|
-
width: 480px
|
44
|
-
dl
|
45
|
-
color: #777777
|
46
|
-
font-size: 0.9em
|
47
|
-
dt
|
48
|
-
font-weight: bold
|
49
|
-
float: left
|
50
|
-
dd
|
51
|
-
float: right
|
52
|
-
margin: 0
|
53
|
-
width: 420px
|
54
|
-
|
55
|
-
header, footer
|
56
|
-
// display: block for browsers with poor HTML5 support
|
57
|
-
display: block
|
58
|
-
|
59
|
-
header
|
60
|
-
border-bottom: 1px solid #cccccc
|
61
|
-
overflow: hidden
|
62
|
-
padding-bottom: 0.5em
|
63
|
-
margin-bottom: 1em
|
64
|
-
+box-shadow(0, 1px, 0, #f6f6f6)
|
65
|
-
|
66
|
-
footer
|
67
|
-
border-top: 1px solid #cccccc
|
68
|
-
color: #999999
|
69
|
-
font-size: 0.9em
|
70
|
-
padding: 1em
|
71
|
-
.subscribe
|
72
|
-
float: left
|
73
|
-
a
|
74
|
-
margin-right: 1em
|
75
|
-
.add
|
76
|
-
float: right
|
77
|
-
.fork
|
78
|
-
clear: both
|
79
|
-
font-size: 0.8em
|
80
|
-
|
81
|
-
a:link, a:visited
|
82
|
-
color: #8aa0b6
|
83
|
-
|
84
|
-
h1, h2, h3, h4
|
85
|
-
margin: 0
|
86
|
-
text-shadow: 0 1px 0 white
|
87
|
-
|
88
|
-
h1
|
89
|
-
color: #666666
|
90
|
-
font-size: 1.8em
|
91
|
-
float: left
|
92
|
-
|
93
|
-
h2
|
94
|
-
color: #999999
|
95
|
-
font-size: 1em
|
96
|
-
float: right
|
97
|
-
text-transform: uppercase
|
98
|
-
|
99
|
-
h3
|
100
|
-
color: #333333
|
101
|
-
|
102
|
-
h4
|
103
|
-
display: inline
|
104
|
-
font-size: 1em
|
105
|
-
margin-right: 1em
|
106
|
-
|
107
|
-
.date
|
108
|
-
background-color: #cc0000
|
109
|
-
+border-radius(4px)
|
110
|
-
color: white
|
111
|
-
float: left
|
112
|
-
text-align: center
|
113
|
-
padding: 2px
|
114
|
-
width: 60px
|
115
|
-
.day
|
116
|
-
background-color: white
|
117
|
-
color: #333333
|
118
|
-
font-size: 1.6em
|
119
|
-
padding: 0.2em
|