Last active
February 16, 2019 13:36
-
-
Save jgaskins/50b0bc5f0a8cea038e24d9d29dd66129 to your computer and use it in GitHub Desktop.
React Router v4-style routing for Clearwater
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'routing' | |
class Layout | |
include Clearwater::Component | |
include Routing | |
def render | |
div([ | |
nav([ | |
Link.new({ href: '/' }, 'Home'), | |
' ', | |
Link.new({ href: '/articles' }, 'Articles'), | |
' ', | |
Link.new({ href: '/about' }, 'About'), | |
]), | |
# Here's where the magic happens | |
route do | |
match('articles') { Articles.new } | |
match('about') { About.new } | |
miss { h1 'Home page' } | |
end, | |
]) | |
end | |
end | |
class Articles | |
include Clearwater::Component | |
include Routing | |
def render | |
div([ | |
# Display a list of links for each article in the list | |
ul(articles.map { |a| ArticlesListItem.new(a) }), | |
# Note that we don't need to include the full path here. | |
# We just supplement what was already matched. | |
route do | |
match(':id') { 'This does not work yet' } | |
match('foo') { h1 'Matched Foo' } | |
end, | |
]) | |
end | |
def articles | |
Store.state.articles | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Routing | |
attr_accessor :matched_path # The part of the path that's already been matched in parent routes | |
def route | |
@matched = [] # Supports multiple route blocks | |
@path_matcher = PathMatcher.new(matched_path, Bowser.window.location.path) | |
yield | |
@matched | |
end | |
def match path_segment | |
if @path_matcher.match? path_segment | |
@matched << ChildRoute.new(yield, "#{@path_matcher.current_match}/#{path_segment}") | |
end | |
end | |
def miss | |
if @matched.none? | |
@matched << ChildRoute.new(yield, matched_path) | |
end | |
end | |
ChildRoute = Struct.new(:content, :current_path_match) do | |
include Clearwater::Component | |
def render | |
# Allow for plain JS objects but also check to see if we can use the accessor | |
if `!!(#{content} && #{content}.$$class) && #{content.respond_to? :matched_path=}` | |
content.matched_path = current_path_match | |
end | |
content | |
end | |
end | |
class PathMatcher | |
attr_reader :current_match, :current_path | |
def initialize current_match, current_path | |
@current_match = current_match.to_s | |
@current_path = current_path.to_s | |
end | |
def match? segment | |
segment = segment.sub(%r(^/), '') | |
match_check = "#{current_match}/#{segment}" | |
# TODO: handle dynamic segments here | |
if current_path.start_with? match_check | |
true | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment