almanack 0.0.1.alpha3 → 1.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|