Skip to content

Instantly share code, notes, and snippets.

@fritzvd
Last active February 21, 2019 14:19
Show Gist options
  • Save fritzvd/cf5c1596e2aa74f4ec2861e60f8b1996 to your computer and use it in GitHub Desktop.
Save fritzvd/cf5c1596e2aa74f4ec2861e60f8b1996 to your computer and use it in GitHub Desktop.
preferences

RrHN Continued: Adding a preferences form.

Create the preferences forms as it was demo-ed in class. In the preparations folder you'll find some instructions, and the HTML and CSS that should help you along.

Notice the gear-icon in the header of the left-column.
Please ignore the "Mark all items as seen" button and the different colors of the titles in the left-hand column. That will be the next task.

Step 6: Add a component for the Preferences Dialog.

  • Create a React Component for the Preferences dialog. You can, if you want, use the supplied example HTML and CSS as a head-start.
  • Add a boolean to the App state that determines whether the preferences dialog is visible.
  • Change the render-method of App to show the preferences dialog instead of the iframe (or the "No item selected"-screen), iff the boolean you just added to the app state is true.
  • Test whether the PreferencesDialog can be shown in your app.
    If you're using the CSS file we're supplying, don't worry if you lost the color in the app. You'll fix that in step 8.

Step 7: Create local state for the preferences dialog

  • The preferences dialog should copy the current prefs to it's local component state.
  • Add event handlers to both the input field and the select box, to allow the user to change the input of the controlled form elements.
  • If the number of items-field has a value that is < 0 or > 500, give the input field a red border.

Step 8: The App should have prefs.

  • The App should also keep the preferences info in its component state. Give its state two fields for color and list size. Choose appropriate defaults.
  • Make the color field work. If you're using the example HTML and CSS, this should be simple: The App component gets a second CSS-class, based on the color variable in the prefs of App: "orange", "green" and "brown" are supported by the CSS.
  • Make the list size field work: pass the list size reference from App to ItemList as a prop, and have the Itemlist show the required amount of items.
  • Decide how the ItemList will deal with possible 'bad' values of the list size prop (negative, larger than your data-array, not a number).

Step 9: The Preferences Dialog should be initialized from the App preferences.

  • Make sure that whenever the preferences dialog is shown, the values for the input field are initialized according to the corresponding values in App.
  • You'll probably have to give some props to the PreferencesDialog to do this.

Step 10: A button to show the PreferencesDialog

  • Create a button in a header or footer of the ItemList to show the preferences dialog.
  • You can, if you like use the fancy SVG-icon in the example HTML, but you may also simply create a regular HTML-button.
  • This button is part of the ItemList component, but it must change the value in the state of App that controls whether the PreferencesDialog is shown. Create an event handler in App that can be passed to ItemList as a prop to accomplish this. (Make sure the event handler calls setState properly, and is bound correctly).

Step 11: Have the Cancel-button close the dialog.

This step is similar to the previous one.

  • Create an event handler in App that can be passed to PreferencesDialog as a prop that sets the visibility boolean to false. (Make sure the event handler calls setState properly, and is bound correctly).
  • Have the Cancel-button in the PreferencesDialog use that prop as its onClick handler.

Step 12: Have the OK-button update the preferences in the state of App.

  • Create a method (called applyPreferences(color,listSize)) that uses its parameters to update the preferences-data in the state of App (Make sure the event handler calls setState properly).
  • Pass this method (bound properly) as a prop to PreferencesDialog.
  • Give the OK-button in PreferencesDialog a local event handler, whose task is to call the passed-in prop (that points to applyPreferences) with the correct parameters.
  • this local event handler should also close the dialog (using the same callback that the Cancel-button uses.)
html {
font-size: 9pt;
}
body {
margin: 0;
}
a {
color: inherit;
text-decoration: inherit;
}
.App {
color: #444;
font-family: Georgia;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
}
#ListPanel {
box-sizing: border-box;
flex-grow: 1;
flex-shrink: 0.5;
flex-basis: 30vw;
overflow-x: hidden;
overflow-y: auto;
height: 100vh;
}
#ContentPanel {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 70vw;
display: flex;
flex-direction: column;
box-sizing: border-box;
text-align: center;
background-color: #f0f0f0;
}
#ContentPanel.item iframe {
flex-grow: 1;
}
#ContentPanel.empty h2 {
padding-top: 6rem;
font-family: Georgia;
font-size: 1.4rem;
font-weight:normal;
color: #888;
margin:0;
}
#ContentPanel.empty p {
padding-top: 1rem;
font-size: 1rem;
color: #888;
font-style: italic;
margin:0;
}
#ListHeader {
padding-left: 1rem;
}
.settingsIcon {
float:right;
margin: 0.7rem 1.2rem;
display: inline-block;
fill: #bbb;
cursor: pointer;
}
.settingsIcon:hover {
fill: #444;
}
.Logo {
display: inline-block;
}
.Logo .colored {
display: inline-block;
padding: 1rem 0rem;
font-family: 'Arial Black';
font-size: 0.8rem;
letter-spacing: 1pt;
width: 4rem;
box-sizing: border-box;
text-align: center;
}
.orange .Logo .colored {
background-color: #ff8800;
color: #fff;
}
.green .Logo .colored {
background-color: #659f6c;
color: #fff;
}
.brown .Logo .colored {
background-color: #a9916b;
color: #fff;
}
.Logo .title {
display: inline-block;
padding-left: 0.5rem;
color: #000;
font-size: 1rem;
font-style: italic;
}
#ListMainContent {
padding: 1rem 1rem;
}
.mainInfo {
display: inline-block;
padding: 1.3rem 0 1.3rem 0.5rem;
border-bottom: 1px solid #DDD;
/* width: 33rem; */
}
#ListFooter {
color: #999;
font-size: smaller;
padding: 4rem 1rem 1.5rem 2rem;
}
#ListFooter a {
text-decoration: underline;
}
.itemTitle {
font-size: 1.4rem;
}
.orange .Item.new .itemTitle {
color: #ff8800;
}
.green .Item.new .itemTitle {
color: #659f6c;
}
.brown .Item.new .itemTitle {
color: #a9916b;
}
.Item.new.selectedItem .itemTitle {
color: #ee7700;
}
.Item.seen .itemTitle {
color: #444;
}
.Item.read .itemTitle {
color: #999;
}
.Item.selectedItem .itemTitle {
color: #000;
}
.orange .Item.selectedItem {
background-color: #fff0dd;
}
.green .Item.selectedItem {
background-color: #c0e7c5;
}
.brown .Item.selectedItem {
background-color: #e5d6c0;
}
.Item .domain {
color: #999;
}
.Item .info {
color: #999;
padding-top: 0.4rem;
font-style: italic;
}
.Item .comments {
color: #888;
background-color: #f0f0f0;
padding: 0.1rem .5rem;
border-radius: .3rem;
border: 1px solid #ddd;
}
.Item .divider {
display: inline-block;
padding: 0rem 0.4rem;
color: #ccc;
}
button {
margin: 0 auto;
font-family: Georgia;
display: block;
padding: 0.5rem 1rem;
font-size: 1.1rem;
border-radius: 0.5rem;
color: black;
cursor: pointer;
box-shadow: 3px 3px 10px 0px rgba(0,0,0,0.22);
}
.orange button {
background-color: #fff0dd;
border: 1px solid #ff8800;
}
.green button {
background-color: #c0e7c5;
border: 1px solid #659f6c;
}
.brown button {
background-color: #e5d6c0;
border: 1px solid #a9916b;
}
#markAsSeen {
padding: 1rem 3rem;
margin: 3rem auto;
}
.PreferencesDialog {
justify-content: center;
background-color: white;
border: 1px solid #ccc;
padding: 0rem 3rem 3rem 3rem;
margin: auto auto;
width: 80%;
max-width: 35rem;
font-size: 1.1rem;
box-shadow: 10px 10px 50px 0px rgba(0,0,0,0.2);
}
.PreferencesDialog header {
text-align: left;
margin-bottom: 3rem;
}
.PreferencesDialog label {
display:block;
margin: 2rem 0 0 0;
text-align: left;
}
.PreferencesDialog .warning {
font-size: 0.8rem;
text-align: left;
padding-top: 0.2rem;
font-style: italic;
}
.dialogButtons {
text-align: center;
}
.PreferencesDialog button {
display:inline-block;
margin-left: 1rem;
}
<html>
<head>
<!-- Like all static assests, '/css/main.css' will be sought in the 'dist' directory -->
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<!-- this div is where all the react components will be inserted -->
<div id="react-root">
<div data-reactroot="" class="App orange">
<div id="ListPanel">
<div class="ItemList">
<header id="ListHeader" class="panelHeader">
<div class="Logo">
<div class="colored">RrHN</div>
<div class="title">React-redux Hacker News</div>
</div>
<span class="settingsIcon">
<svg width="20" height="20" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
<path d="M1152 896q0-106-75-181t-181-75-181 75-75 181 75 181 181 75 181-75 75-181zm512-109v222q0 12-8 23t-20 13l-185 28q-19 54-39 91 35 50 107 138 10 12 10 25t-9 23q-27 37-99 108t-94 71q-12 0-26-9l-138-108q-44 23-91 38-16 136-29 186-7 28-36 28h-222q-14 0-24.5-8.5t-11.5-21.5l-28-184q-49-16-90-37l-141 107q-10 9-25 9-14 0-25-11-126-114-165-168-7-10-7-23 0-12 8-23 15-21 51-66.5t54-70.5q-27-50-41-99l-183-27q-13-2-21-12.5t-8-23.5v-222q0-12 8-23t19-13l186-28q14-46 39-92-40-57-107-138-10-12-10-24 0-10 9-23 26-36 98.5-107.5t94.5-71.5q13 0 26 10l138 107q44-23 91-38 16-136 29-186 7-28 36-28h222q14 0 24.5 8.5t11.5 21.5l28 184q49 16 90 37l142-107q9-9 24-9 13 0 25 10 129 119 165 170 7 8 7 22 0 12-8 23-15 21-51 66.5t-54 70.5q26 50 41 98l183 28q13 2 21 12.5t8 23.5z"></path>
</svg>
</span>
</header>
<div id="ListMainContent">
<div class="Item seen">
<div class="mainInfo">
<div>
<a class="itemTitle" href="https://github.com/fatiherikli/language-evolution-simulation">Show HN: Language Evolution Simulation</a>
<span class="domain">
&emsp;(github.com, seen before)
</span>
</div>
<div class="info">
18 points<span class="divider">|</span>by fatiherikli<span class="divider">|</span>July 18, 2016<span class="divider">|</span>
<a class="comments" href="https://news.ycombinator.com/item?id=12115187">
<strong>665</strong> comments
</a>
</div>
</div>
</div>
<div class="Item new">
<div class="mainInfo">
<div>
<a class="itemTitle" href="https://d4.js.org">D4 &mdash; Declarative Data-Driven Documents</a>
<span class="domain">
&emsp;(d4.js.org, new!)
</span>
</div>
<div class="info">
62 points<span class="divider">|</span>by joelburget<span class="divider">|</span>July 18, 2016<span class="divider">|</span>
<a class="comments" href="https://news.ycombinator.com/item?id=12114716">
<strong>19</strong> comments
</a>
</div>
</div>
</div>
<div class="Item read">
<div class="mainInfo">
<div>
<a class="itemTitle" href="https://vulkan-tutorial.com/Introduction">Vulkan Tutorial</a>
<span class="domain">
&emsp;(vulkan-tutorial.com, already read)
</span>
</div>
<div class="info">
124 points<span class="divider">|</span>by Bambo<span class="divider">|</span>July 18, 2016<span class="divider">|</span>
<a class="comments" href="https://news.ycombinator.com/item?id=12114440">
<strong>9</strong> comments
</a>
</div>
</div>
</div>
<div class="Item seen">
<div class="mainInfo">
<div>
<a class="itemTitle" href="http://papers.ssrn.com/sol3/papers.cfm?abstract_id=2807046">The Empirical Economics of Online Attention</a>
<span class="domain">
&emsp;(papers.ssrn.com, seen before)
</span>
</div>
<div class="info">
28 points<span class="divider">|</span>by Dowwie<span class="divider">|</span>July 18, 2016<span class="divider">|</span>
<a class="comments" href="https://news.ycombinator.com/item?id=12114644">
<strong>9237</strong> comments
</a>
</div>
</div>
</div>
</div>
<button id="markAsSeen">Mark all items as &quot;seen&quot;</button>
<footer id="ListFooter">
visual design based on <a href="http://blog.trackduck.com/weekly/top-10-hacker-news-redesigns/unknown-author-2/">this redesign by unknown author</a>.
</footer>
</div>
</div>
<div id="ContentPanel" class="preferences">
<div class="PreferencesDialog">
<header>
<div class="Logo">
<div class="colored">RrHN</div>
<div class="title">Settings</div>
</div>
</header>
<label for="listSizeField">
Show <input type="number" id="listSizeField" value="42"> items in the list.
</label>
<label for="colorField">
color:
<select id="colorField">
<option>orange</option>
<option>green</option>
<option>brown</option>
</select>
</label>
<div class="dialogButtons"><button>OK</button><button>Cancel</button></div>
</div>
</div>
</div>
</div>
<!-- This bundle.js file will be created by Webpack as it combines all the JS modules. -->
<!-- It should be created in the 'dist' directory, like this html-file. -->
<script src="bundle.js"></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment