Skip to content

Instantly share code, notes, and snippets.

@martinklepsch
Created January 11, 2016 18:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinklepsch/c63b65a7d35fd689587a to your computer and use it in GitHub Desktop.
Save martinklepsch/c63b65a7d35fd689587a to your computer and use it in GitHub Desktop.
// The flag object shares a lot of common traits with the media
// object; its sole purpose is displaying image- and text-like content
// side-by-side. Where the flag object differs, however, is its ability
// to vertically align the image and text to the tops, middles or bottoms
// of each other.
//
// http://csswizardry.com/2013/05/the-flag-object/
.flag
display: table
width: 100%
.flag__image, .flag__body
display: table-cell
// border: 1px solid red
vertical-align: middle
&--top
.flag__image, .flag__body
vertical-align: top
&--bottom
.flag__image, .flag__body
vertical-align: bottom
.flag__image
padding-right: 10px
> img
display: block
max-width: none
.flag--rev &
padding-right: 0
padding-left: 10px
.flag__body
width: 100%
(ns app.flag
(:require [reagent.core :as reagent :refer [atom]]))
(defn flag
"Simple flag object component as described by Harry Roberts:
http://csswizardry.com/2013/05/the-flag-object"
[& {:keys [image bodies]}]
[:div.flex.flex-center
[:div.flex-none.mr3 image]
[:div.flex-auto (first bodies)]
(if-let [b (second bodies)]
[:div.flex-none.px2 b])])
(defn expandable-flag
"An extension of the flag object that will maintain initial
positioning even if flag body expands.
Example (note the +/~ difference):
+-----+
| (I) | ++++++++++++++
+-----+
If the flag body is being expanded the vertical centering would
be maintained, causing a jump of the flag image (I):
++++++++++++++
+-----+ ~~ ~~~~~~~~~
| (I) | ~~~~~~ ~~~~~
+-----+ ~~ ~~~~~~~~~
~~~~~ ~~~
Now the expandable flag object maintains the initial positioning,
avoiding any jumps while still achieving perfect vertical alignment
of the unexpanded flag (keep in mind that the ++ lines could also be
higher than the image):
+-----+
| (I) | ++++++++++++++
+-----+ ~~ ~~~~~~~~~
~~~~~~ ~~~~~
~~ ~~~~~~~~~
~~~~~ ~~~
--- Keyword Arguments ---
- `image`: simple component which will be rendered as flag image
- `bodies`: list of body components. Either plain components or
components taking a boolean `expanded` parameter
- `expanded?`: Whether the flag is currently expanded or not
--- Caveat ---
This uses a local atom to store state and any remounting,
as it's done by Figwheel and the likes, will cause the values to be reset.
Depending on the state the flag is in this can result in odd behaviour.
(Should only ever occur in live-reloading workflows.)"
[& {:keys [image bodies expanded?]}]
(let [pads (atom [])
pad (fn [ex i] {:style {:padding-top (if ex (str (get @pads i) "px"))}})]
(reagent/create-class
{:component-did-mount
(fn [cmpnt]
(when (and (empty? @pads) (not expanded?))
(let [h (.-offsetHeight (reagent/dom-node cmpnt))
c (array-seq (.-children (reagent/dom-node cmpnt)))
ps (mapv #(/ (- h (-> % .-firstChild .-offsetHeight)) 2) c)]
(reset! pads ps))))
:reagent-render
(fn [& {:keys [image bodies expanded?]}]
[:div.flag {:class (if expanded? "flag--top")}
[:div.flag__image (pad expanded? 0) image]
(doall
(map-indexed (fn [i b]
^{:key i}
[:div.flag__body
(pad expanded? (inc i))
(if (fn? b) [b expanded?] b)])
bodies))])})))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment