{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import panel as pn\n",
    "import numpy as np\n",
    "import holoviews as hv\n",
    "\n",
    "pn.extension(sizing_mode = 'stretch_both')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For a large variety of use cases we do not need complete control over the exact layout of each individual component on the page, as could be achieved with a [custom template](../../user_guide/Templates.ipynb), we just want to achieve a more polished look and feel. For these cases Panel ships with a number of default templates, which are defined by declaring four main content areas on the page, which can be populated as desired:\n",
    "\n",
    "* **`header`**: The header area of the HTML page\n",
    "* **`sidebar`**: A collapsible sidebar\n",
    "* **`main`**: The main area of the application\n",
    "* **`modal`**: A modal area which can be opened and closed from Python\n",
    "\n",
    "These four areas behave very similarly to other Panel layout components and have list-like semantics. The `ReactTemplate` in particular however is an exception to this rule as the `main` area behaves like panel `GridSpec` object. Unlike regular layout components however, the contents of the areas is fixed once rendered. If you need a dynamic layout you should therefore insert a regular Panel layout component (e.g. a `Column` or `Row`) and modify it in place once added to one of the content areas. \n",
    "\n",
    "Templates can allow for us to quickly and easily create web apps for displaying our data. Panel comes with a default Template, and includes multiple Templates that extend the default which add some customization for a better display.\n",
    "\n",
    "#### Parameters:\n",
    "\n",
    "In addition to the four different areas we can populate the `ReactTemplate` declares a few variables to configure the layout:\n",
    "\n",
    "* **`cols`** (dict): Number of columns in the grid for different display sizes (`default={'lg': 12, 'md': 10, 'sm': 6, 'xs': 4, 'xxs': 2}`)\n",
    "* **`breakpoints`** (dict): Sizes in pixels for various layouts (`default={'lg': 1200, 'md': 996, 'sm': 768, 'xs': 480, 'xxs': 0}`)\n",
    "* **`row_height`** (int, default=150): Height per row in the grid\n",
    "* **`dimensions`** (dict): Minimum/Maximum sizes of cells in grid units (`default={'minW': 0, 'maxW': 'Infinity', 'minH': 0, 'maxH': 'Infinity'}`)\n",
    "* **`prevent_collision`** (bool, default=Flase): Prevent collisions between grid items.\n",
    "* **`save_layout`** {bool, default=False): Save layout changes to localStorage.\n",
    "\n",
    "These parameters control the responsive resizing in different layouts. The `ReactTemplate` also exposes the same parameters as other templates:\n",
    "\n",
    "* **`busy_indicator`** (BooleanIndicator): Visual indicator of application busy state.\n",
    "* **`header_background`** (str): Optional header background color override.\n",
    "* **`header_color`** (str): Optional header text color override.\n",
    "* **`logo`** (str): URI of logo to add to the header (if local file, logo is base64 encoded as URI).\n",
    "* **`site`** (str): Name of the site. Will be shown in the header. Default is '', i.e. not shown.\n",
    "* **`site_url`** (str): Url of the site and logo. Default is \"/\".\n",
    "* **`title`** (str): A title to show in the header.\n",
    "* **`theme`** (Theme): A Theme class (available in `panel.template.theme`)\n",
    "* **`sidebar_width`** (int): The width of the sidebar in pixels. Default is 350.\n",
    "\n",
    "________"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this case we are using the `ReactTemplate`, built on  [react-grid-layout](https://github.com/STRML/react-grid-layout), which provides a responsive, resizable, draggable grid layout. Here is an example of how you can set up a display using this template:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "react = pn.template.ReactTemplate(title='React Template')\n",
    "\n",
    "xs = np.linspace(0, np.pi)\n",
    "freq = pn.widgets.FloatSlider(name=\"Frequency\", start=0, end=10, value=2)\n",
    "phase = pn.widgets.FloatSlider(name=\"Phase\", start=0, end=np.pi)\n",
    "\n",
    "@pn.depends(freq=freq, phase=phase)\n",
    "def sine(freq, phase):\n",
    "    return hv.Curve((xs, np.sin(xs*freq+phase))).opts(\n",
    "        responsive=True, min_height=400)\n",
    "\n",
    "@pn.depends(freq=freq, phase=phase)\n",
    "def cosine(freq, phase):\n",
    "    return hv.Curve((xs, np.cos(xs*freq+phase))).opts(\n",
    "        responsive=True, min_height=400)\n",
    "\n",
    "react.sidebar.append(freq)\n",
    "react.sidebar.append(phase)\n",
    "\n",
    "# Unlike other templates the `ReactTemplate.main` area acts like a GridSpec \n",
    "react.main[:4, :6] = pn.Card(hv.DynamicMap(sine), title='Sine')\n",
    "react.main[:4, 6:] = pn.Card(hv.DynamicMap(cosine), title='Cosine')\n",
    "\n",
    "react.servable();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With the `row_height=150` this will result in the two `Card` objects filling 4 rows each totalling 600 pixels and each taking up 6 columns, which resize responsively to fill the screen and reflow when working on a smaller screen. When hovering of the top-left corner of each card a draggable handle will allow dragging the components around while a resize handle will show up at the bottom-right corner."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3><b>ReactTemplate with DefaultTheme</b></h3>\n",
    "<img src=\"../../assets/React.png\" style=\"margin-left: auto; margin-right: auto; display: block;\"></img>\n",
    "</br>    \n",
    "<h3><b>ReactTemplate with DarkTheme</b></h3>\n",
    "<img src=\"../../assets/ReactDark.png\" style=\"margin-left: auto; margin-right: auto; display: block;\"></img>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The app can be displayed within the notebook by using `.servable()`, or rendered in another tab by replacing it with `.show()`. \n",
    "\n",
    "Themes can be added using the optional keyword argument `theme`. Each template comes with a DarkTheme and a DefaultTheme, which can be set `ReactTemplate(theme=DarkTheme)`. If no theme is set, then DefaultTheme will be applied.\n",
    "\n",
    "It should be noted that Templates may not render correctly in a notebook, and for the best performance the should ideally be deployed to a server."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
