Giter Site home page Giter Site logo

infinitered / thesis-phoenix Goto Github PK

View Code? Open in Web Editor NEW
648.0 39.0 62.0 3.92 MB

A lightweight, bolt-on, intuitive content editing system for Elixir/Phoenix websites. Star this repo and follow along with our progress!

License: Other

Elixir 49.21% JavaScript 31.83% HTML 0.06% Shell 2.11% Sass 10.84% SCSS 5.95%
elixir elixir-lang elixir-phoenix elixir-library content-management-system

thesis-phoenix's Introduction

Thesis

Why is this archived?

We really appreciate all the community support in the years since we first released thesis-phoenix. Our focus has shifted from Elixer/Phoenix to React Native. Feel free to fork this library and continue on its legacy if you want.

What Is Thesis?

A CMS for Elixir/Phoenix that doesn't hijack your development workflow.

Thesis is a lightweight and flexible Elixir/Phoenix CMS for quickly and easily adding content editing to any page on a Phoenix website, as well as creating new dynamically routed pages. It's ideal for either adding limited editing support to existing Phoenix websites or building dynamic websites.

Watch Jamon Holmgren give a 5-minute lightning talk about Thesis at ElixirConf 2017: https://www.youtube.com/watch?time_continue=2656&v=YqOwzXNkOyg

Thesis Features

  1. Elixir/Phoenix hex package, uses React.js for its user interface
  2. Lightweight, bolt-on, doesn't hijack your development workflow
  3. On-page rich text editing
  4. On-page plain text editing
  5. Raw HTML editing for Youtube embeds or other flexible uses
  6. Image URL editing, both img tag and div with background image
  7. Page meta title and description editing
  8. Easily bring your own authentication system in one tiny function
  9. Create new dynamic pages, delete dynamic pages

What Thesis Isn't

Thesis isn't the same as other -bloated- full-function content management systems out there. This is a list of what it's not now and not likely to be in the future.

  • Not a complete WordPress Replacement
  • Not a full featured CMS
  • Not a full featured WYSIWYG editor
  • Not an authentication or permission system
  • Not supported outside of a Phoenix app

screen capture on 2016-04-20 at 15-11-10 copy


If you are having problems, view README_INSTALL.md for manual instructions.

1. Add thesis to your mix.exs:
def deps do
  [{:thesis, "~> 0.3.4"}]
end
2. Run mix thesis.install

This install script will add Thesis to your config/config.exs and lib/yourapp_web.ex, as well as generate migrations and an authorization module in your lib/thesis_auth.ex.

3. Add the Thesis editor to your layout
  <body>
    <%= thesis_editor(@conn) %>
4. Run mix ecto.migrate
$ mix ecto.migrate


Check out the example apps in examples/ to see how Thesis can be implemented. We'll keep this up to date with examples of the latest features as we develop Thesis.


Use the Thesis.View.content/4 view helper function to make a content area editable. If you have use Thesis.View in your lib/yourapp_web.ex file, this function is already available on all of your views.

Thesis will add a wrapper <div> around editable HTML and plain-text content areas, both in read mode and edit mode, so plan your CSS accordingly.

Rich Text Areas

Simply wrap your HTML in a content function call, specifying html as the content type.

<h1>Title</h1>
<p>
  Here's my default description!
</p>

becomes...

<%= content(@conn, "Section identifier", :html) do %>
  <h1>Title</h1>
  <p>
    Here's my default description!
  </p>
<% end %>

Custom HTML Editor

Don't like the MediumEditor? Write your own custom editor implementing the common editor interface.

class MyCustomEditor {
  constructor(opts) {
    this.onChange = opts.onChange;
  }
  enable() {} // Setup Editor
  disable() {} // Teardown Editor
  content(editor) {} // Return content
  set(name, data) {} // Set content
}

For more detail, check out HtmlEditor or this gist implementing a custom editor using Trumbowyg.

To enable, add this in your config/config.exs file:

config :thesis,
  html_editor: "MyCustomEditor"


Plain Text Areas

For plain-text, provide a do: option for default text.

<h1>My Title</h1>

becomes...

<h1><%= content(@conn, "Title identifier", :text, do: "My Title") %></h1>


Custom HTML Areas

For video embeds, iframes, and any other custom HTML, use the :raw_html content type:

<iframe width="560" height="315" src="https://www.youtube.com/embed/5SVLs_NN_uY" frameborder="0" allowfullscreen></iframe>

becomes...

<%= content(@conn, "Section identifier", :raw_html) do %>
  <iframe width="560" height="315" src="https://www.youtube.com/embed/5SVLs_NN_uY" frameborder="0" allowfullscreen></iframe>
<% end %>


Images

You can have the user specify an image URL and display the image with the image content type.

<img src="http://placekitten.com/200/300">

becomes...

<%= content(@conn, "Image identifier", :image, alt: "My alt tag", do: "http://placekitten.com/200/300") %>

If you prefer to use a div with a background image, you can use the background_image content type.

<div style="background-image: url(http://placekitten.com/200/300)"></div>

becomes...

<%= content(@conn, "Image identifier", :background_image, do: "http://placekitten.com/200/300") %>

Image Uploads

Thesis offers support for a few different ways to handle image uploads: store files in the database, point to an uploader/adapter inside your custom app, or use one of the prebuilt adapters (in progress).

Store Files in Database

For smaller websites and/or website that are hosted on the cloud, thesis offers a no-setup-required image uploader. Files are stored in a separate table and contain all of the needed metadata (name, file type, and blobs themselves). Keep in mind as you upload more and more files, your database will grow quickly. Don't use this for high-traffic, content-heavy web applications. Smaller personal websites are probably fine.

To enable, add this in your config/config.exs file:

config :thesis,
  uploader: Thesis.RepoUploader
Use Your Own Uploader Module

If you already set up file uploads in your custom app, point thesis to a module that can handle a %Plug.Upload{} struct.

config :thesis,
  uploader: <MyApp>.<CustomUploaderModule>

The module should have an upload/1 function that accepts a %Plug.Upload{} struct. This function should return either {:ok, "path/to/file.jpg"} tuple with an image url or path, or {:error, _}. You can view /lib/thesis/uploaders/repo_uploader.ex for an example.

That's it! Restart your server and image content areas will now contain a file upload field.


Global Content Areas

Content areas in Thesis are page-specific. However, if you want an editable area that can be displayed on multiple pages, use the Thesis.View.global_content/4 function. Any page using that content area identifier will display the edited content across the whole website.

<%= global_content(@conn, "Footer Text", :html) do %>
  <h4>Contact Info</h4>
  <ul>
    <li>Call us at (800) 555-1212</li>
    <li>Email us at [email protected].</li>
  </ul>
<% end %>

Custom Classes or ID

Thesis adds an additional <div> around your editable content areas. We suggest that you not style these divs heavily, since Thesis uses them as editors and adds its own styles in edit-mode. However, sometimes, you need to modify that markup slightly for better presentation. You can provide an ID and additional classes by specifying id and classes, respectively.

<%= content(@conn, "Ident", :html, id: "my-id", classes: "more classes") do %>
  <h1>Title</h1>
<% end %>


Page Meta Title and Description

Thesis provides a settings tray to edit each page's title and description. In your layout, you can output the current title and description like so:

<title><%= page_title(@conn, "Default Title") %></title>
<meta name="description" content="<%= page_description(@conn, "Default Description") %>" />

Some prefer to set the page title and description as assigns in their controller actions:

def about(conn, params) do
  @title = Thesis.View.page_title(conn, "About My Company")
  @description = Thesis.View.page_description(conn, "A relevant description here.")
end


Thesis supports users creating and deleting dynamically routed pages. These differ from static pages in that they are routed by Thesis rather than Phoenix, and live only in your database. They can be rendered with different templates.

add new page screenshot

To enable dynamic pages, add (or uncomment) this in your config/config.exs file:

config :thesis, :dynamic_pages,
  view: <MyApp>.PageView,
  templates: ["index.html", "otherview.html"],
  not_found_view: <MyApp>.ErrorView,
  not_found_template: "404.html"

Replace <MyApp> with your app name. Use any view you want, and put any templates contained in that view that you want to make available in the templates list. These will be displayed as a drop-down to the user when they are creating the new dynamic page.

You'll also need to make one change to your router.ex and a controller of your choice.

# web/router.ex
# should be added as the last route

  get "/*path", <MyApp>.PageController, :dynamic

# web/controllers/page_controller.ex (or similar)

  def dynamic(conn, _params) do
    render_dynamic(conn)
  end

You can pass in a default template (otherwise, it'll use the first template option in your config) with render_dynamic(conn, template: "index.html").

You can choose to make only a portion of your website support dynamic pages by routing more specifically. For example, if you want a blog section:

# web/router.ex

  get "/blog/*path", <MyApp>.BlogController, :dynamic


You probably don't want your website editable by the world. Thesis doesn't force you to use any particular authorization strategy.

Instead, Thesis will call your auth module's page_is_editable?/1 function and provide the current conn, which can be used to extract current user session data as well as the current page, and then you can decide how that should affect authorization.

Here's an example which we use on our own website, https://infinite.red:

defmodule IrWebsite.ThesisAuth do
  @behaviour Thesis.Auth

  def page_is_editable?(conn) do
    IrWebsite.AuthController.logged_in?(conn)
  end
end

In our auth_controller.ex file, the logged_in?/1 function looks something like this:

  def logged_in?(conn) do
    !!current_user(conn)
  end

  def current_user(conn) do
    get_session(conn, :current_user)
  end

So, in this case, we're simply checking to see if the user has been logged in or not. Since only Infinite Red employees have logins, it's safe for us to assume that if they're logged in, they have permission to edit the page.

If you use Guardian or something similar, you may need additional manipulations to your conn to properly authenticate the user. Add those to your auth module like this:

defmodule MyApp.ThesisAuth do
  @moduledoc """
  Contains functions for handling Thesis authorization.
  """

  def page_is_editable?(conn) do
    conn
    |> Guardian.Plug.VerifySession.call(%{})
    |> Guardian.Plug.LoadResource.call(%{})
    |> MyApp.SessionController.logged_in_and_admin?
  end
end


Notifications/alerts allow us to talk with the user about the various aspects of the editing experience. For us, the contributors, this means that we may warn the user or developer of a breaking change that requires migrations (if they were forgotten to be executed). Since this is configurable, the developer may elect to push custom notifications to various parts of the Thesis editor.

Notifications can be configured to be static:

config :thesis, :notifications,
  page_settings: ["The changes made here will affect your SEO", "Example notification 2"],
  add_page: ["You are about to add a new page to the product site!"],
  import_export_restore: ["Example notification 4"]

Or, you may elect to add some logic and make them more dynamic:

config :thesis, :notifications,
  page_settings: ["Example notification 1", "Example notification 2"],
  add_page: &MyApp.CustomModule.generate_notifications/1,
  import_export_restore: &MyApp.CustomModule.import_warning/1

In either case, there are only 2 things that matter: 1 - you must provide a List of String(s) for each notification type, whether static or the result of a custom function; 2 - if you are using a custom function, it must be able to accept 1 argument: a %Plug.Conn{} struct. You can see an example here.

Note: right now, there are 3 spots to which you can push notifications: the 'Add New Page' tray, 'Page Settings' tray, and 'Import/Export/Restore' tray. As more features are developed, the notifications will be extended to support those features as well.



Thesis's menu/editor/tray is borked

This is pretty common. While we try to be good citizens by properly namespacing all Thesis elements, we embed Thesis code into your existing web page, and so we're at the mercy of your application's existing CSS.

Inspect the element(s) that are screwed up and see if any of your styles are conflicting. For example, here's a screenshot of an issue:

borked Thesis editor

Note that there is a .tooltip CSS rule originating in a different CSS file that is affecting our editor.

In future releases, we will namespace all Thesis classes and IDs. But if your application is overriding whole elements (like div or img), it's up to you to fix the issue in your own CSS.


We're committed to making Thesis the go-to content editing system for Phoenix websites. Please help us improve!

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Run npm run webpack during development
  5. Use the apps/example Phoenix app to manually test your feature
  6. Write tests for your new feature
  7. Run ./bin/ci in the root directory to ensure that Thesis tests pass.
  8. Push to the branch (git push origin my-new-feature)
  9. Create new Pull Request

Thesis Phoenix, as an open source project, is free to use and always will be. Infinite Red offers premium Thesis Phoenix support and general web app design/development services. Email us at [email protected] to get in touch with us for more details.


Jamon Holmgren Yulian Glukhenko Ken Miller Daniel Berkompas

Also supported by others on the Infinite Red team.


Copyright (c) 2016 Infinite Red, Inc.

Thesis depends on Elixir, which is under the Apache 2 license, and Phoenix, which is MIT.

See LICENSE.md for more information.

thesis-phoenix's People

Contributors

aaronrenner avatar balt87 avatar darinwilson avatar derekgreenberg avatar developit avatar devshane avatar gazler avatar jamonholmgren avatar kemiller avatar keybits avatar manusajith avatar mattvanhorn avatar mikeandrianov avatar optikfluffel avatar robinheinze avatar ryanlntn avatar sandeshsoni avatar seb3s avatar silasjmatson avatar thiamsantos avatar yulolimum avatar zberkom avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

thesis-phoenix's Issues

:classes option doesn't work if followed by a do block

@jamonholmgren - I dont think this actually works: https://github.com/infinitered/thesis-phoenix#custom-classes-or-id

<%= content(@conn, "test", :html, classes: "test-class") do %>
  <p>
          Quem firmissimum ullamco quae esse e commodo de incurreret o
          deserunt. Nam e domesticarum, incurreret dolor est officia cohaerescant, de aut
          instituendarum se probant aliqua eram occaecat duis ea nostrud consectetur non
          mentitum, vidisse magna laboris constias, elit officia aut adipisicing ab de
          quorum aute malis officia.
  </p>
<% end %>

However, this works:

<%
  placeholder = """
    <p>At vero eos et accusamus et iusto odio dignissimos
    ducimus qui blanditiis praesentium voluptatum deleniti
    atque corrupti quos dolores.</p>
  """
%>

<%= content(@conn, "test", :html, do: placeholder, classes: "test-class") %>

Every content block is now a global block

This started happening in the latest version.

Every area is now global:

I did a test... I cleared the database and did a fresh page edit and save. This is what the database looks like after the save.

The page id is null, even though the areas are regular areas, not global:

@jamonholmgren

Discussion - Should changing the content type succeed without providing a new name?

Say we have a text area.. Client wants to change it to a html area AFTER they already added content to the area.

Right now, the area doesn't change. You make the code changes, but when you edit the page, the area is still a text area.

The solution right now is to change the area name AND copy the content over manually. I usually just add append the version number of the area - e.g. Sidebar Heading ---> Sidebar Heading (version2).

@jamonholmgren

Global Area Support

With Concrete5, we had the ability to define a GlobalArea vs a PageArea. With global areas, you would edit the content once, and it would propagate the changes to all pages that used it. A nice to have.

@jamonholmgren

Updating the path on a dynamic page creates a new copy

  1. Create a new dynamic page
  2. Edit that page's path
  3. There will now be two of those pages, one at each path

Possible solutions:

  1. Make "moving" or "copying" a page a separate operation.
  2. When "move" is selected, give an option to forward the old location to the new location. This will actually make a copy and modify the original to have a redirectURL to the new copy.
  3. When "copy" is selected, just copy it with no redirectURL.

Thoughts @yulianglukhenko @kemiller ?

Normalize slug before retrieving page

Problem: If you have a trailing slash or double slash at beginning of the slug, Thesis will think it's a new page.

Solution: Let's normalize the path to have no trailing slash nor double-slash at beginning. Probably needs to be done just before this line of code.

Support Safari

There's an issue in Safari ( @yulolimum can provide more details) and we should support it. (also IE, Edge, Firefox, Brave, but let's start with Safari ).

Global area will not propagate to pages that have not yet been edited

If you have a global area (say, footer copyright text). You make a change to it on the home page and go to the about page. Now, the only way the copyright text will propagate to that page is if it has been edited in the past (if it has an entry in the the thesis_pages table). If it hasn't, it'll display the default content specified in the do: block.

Steps to reproduce.
1- create 3 pages with the global area
2- on pages 1 and 2, click on the Thesis edit square, click Save
3- make a change to the global area on page 1
4- go to page 2 and see the change reflected
5- go to page 3 and be disappointed
6- (bonus) edit the global area on page 3 and see it propagate to all 3 pages

@jamonholmgren

Can create a page with the same slug as a static page

To reproduce:

  1. Have a static page in the routes, but don't save it. This means that it's not in the database.
  2. Create a new dynamic page with the same URL as the static page.

This has some odd consequences.

  1. The static template is rendered, but with the dynamic page's content.
  2. You can delete the page, which clears all the content areas, but doesn't delete the static page.

I'm not sure there's a way to detect this. The page isn't being rendered by Thesis's dynamic router. The page and page content areas are loaded in a plug, before the page is even routed.

We could "distrust" a dynamic page unless render_dynamic is called on it, and otherwise treat it as static. Only mark it as dynamic if render_dynamic is called. This would have the benefit of being more reliable than just looking at the template attribute, which I've never been particularly happy with.

Thesis fails to save content if page description length is > 255

I tried editing a content area, but it would not save because the page description exceeded the allowed char length. I think the field type for page description should be text. Thesis isn't made to enforce SEO best-practices and it would be a bummer if a client tried adding a really long page description and it would fail.

In my case, this was a client-provided default page description to be used on all pages.

@jamonholmgren

Remove Ospry

Ospry doesn't appear to be actively supported and we're finding it's unreliable. Let's remove it entirely from Thesis.

Switch to a more powerful WYSIWYG editor

The current editor doesn't allow editing source which can be quite a hassle. I suggests we switch to using Trumbowyg which has been working well for us in some other applications.

Allow people to add tags to a content area

A cool feature would be to allow people to tag a content area and open up those tags for the dev to use to alter added content.

A couple examples:

You have a text content area to output an alert on the page. The dev would add the following to the content area: tags: %{type: :single, items: ["danger", "warning", "info"]}. There would be some kind of intuitive way of displaying them on the front-end for users to select (in this case only one option). After the users make a selection, in this case, the dev could ouput the selected tag as a className on the div (to change background color with css).

Another example would be for image alignment: tags: %{type: :single, items: ["center", "center top", "center bottom"]}. The dev would then output the selection as an inline style on the div.

As for a different case for the type: %{type: :multiple, items: ["one-bedroom", "two-bedroom", "one-bath", "two-bath", "single-story", "two-story"]. This would allow the user to select more than one tag, in the case that the dev is building a filter.

@jamonholmgren

Issue when saving

Env: dev
Version: 0.0.15

This is the ThesisAuth module:

defmodule IcityMortgage.ThesisAuth do
  @moduledoc """
  Contains functions for handling Thesis authorization.
  """

  def page_is_editable?(conn) do
    user = Guardian.Plug.current_resource(conn)
    IO.inspect user
    IO.inspect user.role
    IO.inspect user && user.role == :admin
    user && user.role == :admin
  end
end

Thesis editor is visible after logging in = great:

After editing a content area and saving, I get an error:

As you can see, inspect for user returns nil. Does the session not get passed into the Thesis scope?

@ryanlntn @jamonholmgren

Reorder editor buttons

Currently, the order goes like this:

  • Save
  • Page settings
  • Cancel
  • Add page
  • Delete page
  • Toggle edit

image

I think this makes more sense from a UX standpoint:

  • Add page
  • Delete page
  • Page settings
  • Save
  • Cancel
  • Toggle edit

After using it for a while, I also dislike hover displaying Add and Delete buttons. I think those should only display on click. It feels like there are two "modes" and it's not clear why.

cc @yulianglukhenko

Feature: Image Content Area

We'd like to be able to add images using Thesis. There would be no image gallery; images that are used more than once across the site would either need to be added as a URL or uploaded multiple times, assuming we add the upload capability.

Image content areas could be added like this:

# Static
<img src="/assets/my_image.png" class="my-image large-image" id="my-image" alt="My Image" />

# Editable
<%= content("My Image", :image, src: "/assets/my_image.png", alt: "My Image", id: "my-image") %>

We'll use the Phoenix.HTML.content_tag/3 helper to generate it, pass through the arbitrary attributes, and wrap it in a div (maybe?).

To start with, let's just let them add images using a URL.

Adding a dynamic page with spaces in the path results in 404

To recreate:

  1. Click Add New Page
  2. Make a path with spaces in it, like /this has spaces
  3. Redirects to /this%20has%20spaces and doesn't show the page

We can either force a slugify or attempt to route the path with spaces in it. I vote for the former.

Content Transfer Feature

I ran into this doing the Infinite Red Ignite page. All of the content was done on staging and after deployment, we either had to manually copy paste to production or transfer the db records through navicat.

What would be cool is if there was an Content Export/Import button in the thesis tools. Clicking that would open up the side tray where you would see a export textarea prefilled with serialized data for this page in a format that thesis could recognize when importing. The tray would also have an import textarea where you would paste the data. You could then Apply to import the data (this would change the content on the page). You could then Save.

As far as Thesis Images go, they could be just passed as URLs pointing to the staging with a query string. Thesis would recognize that query string and import them by downloading.

Seems like a very very straightforward task.

Thoughts?

Intermittent duplicate content rows

As reported by @yulolimum, we've run into an intermittent issue where sometimes duplicate rows are created. It's been a real bear to replicate locally. Until we are able to fix this, I'm going to push an update that is more vigorous about checking for duplicates before creating new content rows.

Add more info here as we find any.

Rethink how React manipulates non-React components

I'm not super happy with how we are currently handling non-React components. I'd like to research best practices and come up with some ideas on how we could improve / streamline it.

Examples, most of which should use state, not reach into the DOM:

https://github.com/infinitered/thesis-phoenix/blob/master/web/static/js/thesis-editor.js#L46-L47
https://github.com/infinitered/thesis-phoenix/blob/master/web/static/js/thesis-editor.js#L94
https://github.com/infinitered/thesis-phoenix/blob/master/web/static/js/thesis-editor.js#L131
https://github.com/infinitered/thesis-phoenix/blob/master/web/static/js/content_types/html_editor.js#L7

Perhaps there could be an object outside of the React component that does the dirty DOM queries and gives those as props to the ThesisEditor component. From then on, it's all self-contained.

Thoughts, @kemiller @GantMan @yulianglukhenko @ryanlntn @skellock ?

Move away from Ospry.io as the default simple image host.

Ospry has been very unreliable in production. Service down every few days.

We should investiage alternatives that are just as easy for devs/clients to setup. AWS is the best option but is it easy enough for client to sign up for?

Perhaps, another alternative for a default image host is storing media as blobs in a separate table in the admin.

Allow some "pages" to just be 301 redirects to other URLs

This goes somewhat in hand with #37.

  1. Add additional field, redirect. It's a nilable string field
  2. If this field is nil/empty string, carry on as usual
  3. If this field is filled out, redirect

Question: how do we reach this page while editing? We won't want it to redirect, or we lose the ability to edit it.

We could simply land on the screen and show an alert saying "When not in edit mode, this page redirects to /url/here. Click Okay to follow, or Cancel to edit this page."

cc @yulianglukhenko @kemiller

Template Options and Page Delete Button present on non-dynamic page.

When editing the page settings on a non-dynamic page (e.g. home page), the template options, page path, and redirect input field are all present.

After clicking "Save", the delete button appears on the non-dynamic page.


These options should not before there.

Here's an example of where this is disastrous as of right now. I have a non-dynamic page. I make changes to it. I tweak the meta info (page all of a sudden becomes 'dynamic' and delete button appears). I click on the delete button. The page doesn't actually get deleted, but it resets ALL of the content.

Pretty major bug.


A proposed solution is not to repurpose the page settings tray. Create another tray with its own handlers that's called dynamic page tray.

@jamonholmgren

Feature: export/import

Export

In the settings dialog for any page, have a button to "Export Page Content" and "Export Site Content". These build a simple .json file, structured like this:

{
  meta: {
    generated_at_url: "http://example.com/contacts",
    generated_at: 2015-09-27T18:30:49-0300
  },
  pages: {
    "/": {
      title: "Home page",
      description: "something",
      page_contents: {
        "HEADER": { type: "text", contents: "Welcome to the Jungle!" }, 
        "SIDEBAR": { type: "html", contents: "<p>Whoop whoop</p>" }
      }
    },
    "/about": {
      // ...
    }
  }
}

Import

In the settings dialog for any page, have a button to "Import Page Content" or "Import Site Content".

Questions:

  • When doing Import Page Content, do we only fetch the page that matches the URL of the current page? If there's only one page in the json file, do we just import that one to the current page regardless of what the URL is?
  • When importing the whole site, do we overwrite everything that already exists?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.