• This repository has been archived on 10/Mar/2021
  • Stars
    star
    648
  • Rank 69,480 (Top 2 %)
  • Language
    Elixir
  • License
    Other
  • Created over 8 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

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

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.

More Repositories

1

ignite

Infinite Red's battle-tested React Native project boilerplate, along with a CLI, component/model generators, and more!
TypeScript
17,283
star
2

reactotron

A desktop app for inspecting your React JS and React Native projects. macOS, Linux, and Windows.
TypeScript
14,757
star
3

nsfwjs

NSFW detection on the client-side via TensorFlow.js
JavaScript
7,194
star
4

gluegun

A delightful toolkit for building TypeScript-powered command-line apps.
TypeScript
2,937
star
5

apisauce

Axios + standardized errors + request/response transforms.
JavaScript
2,789
star
6

ignite-bowser

Bowser is now re-integrated into Ignite CLI! Head to https://github.com/infinitered/ignite to check it out.
TypeScript
615
star
7

solidarity

Solidarity is an environment checker for project dependencies across multiple machines.
TypeScript
614
star
8

ignite-andross

The original React Native boilerplate from Infinite Red - Redux, React Navigation, & more
JavaScript
475
star
9

ChainReactApp2017

The official Chain React Conf 2017 App
JavaScript
437
star
10

rmq

RMQ - RubyMotionQuery
HTML
307
star
11

redpotion

We believe iPhone development should be clean, scalable, and fast with a language that developers not only enjoy, but actively choose. With the advent of Ruby for iPhone development the RubyMotion community has combined and tested the most active and powerful gems into a single package called RedPotion
Ruby
234
star
12

cdq

Core Data Query for RubyMotion
Ruby
172
star
13

ChainReactApp2019

The Chain React 2019 Conference App
TypeScript
165
star
14

react-native-mlkit

The definitive MLKit wrapper for React Native and Expo
TypeScript
124
star
15

nsfwjs-mobile

NSFWjs in React Native
JavaScript
112
star
16

ChainReactApp2023

The official Chain React App for #ChainReact2023, written in React Native
TypeScript
110
star
17

reactotron-react-native

Reactotron's react-native client.
TypeScript
110
star
18

ruby-xcdm

Ruby XCDM
Ruby
94
star
19

bluepotion

Like RedPotion, but for Android
Ruby
74
star
20

ProMotion-menu

RubyMotion gem allowing you to easily setup a facebook or Path style hidden slide menu easily with the ProMotion gem.
Ruby
74
star
21

ramdasauce

Ramda smothered in saucy helpers.
JavaScript
69
star
22

awesome-react-testing

React and React Native testing tools and strategies
67
star
23

firebird

Template for Phoenix 1.3 projects
Elixir
66
star
24

phoenix_base

Template project for Phoenix
Elixir
65
star
25

flipper-plugin-reactotron

A plugin for the Flipper desktop application
TypeScript
63
star
26

ignite-cookbook

Ignite Cookbook for React Native
CSS
47
star
27

ignite-example-login

This is an example Ignited app that shows how to integrate a login screen with redux-aware react navigation
JavaScript
47
star
28

solidarity-react-native

Solidarity snapshot plugin for React Native projects
JavaScript
47
star
29

ai-lab

Library of components for TensorFlow.js in web frameworks.
TypeScript
46
star
30

ionicons-version-3-search

Quickly identify IonIcons from version 3, with version 2 names as tags!
JavaScript
41
star
31

apex

Apex: the RubyMotion web framework for OS X.
Ruby
31
star
32

ir-docs

Omnibus Documentation for Infinite Red Opensource
CSS
26
star
33

ignite-ir-boilerplate-2016

[Not supported] A boilerplate for Ignite with best practices we've learned from 2015.
JavaScript
26
star
34

ignite-bowser-examples

This repository is out of date and is archived here for historical purposes only. See current Ignite Bowser for more relevant examples.
TypeScript
26
star
35

maybe

Access Elixir maps and structs, protected from `nil`
Elixir
25
star
36

open-source

Information and Guides for Infinite Red Open Source Projects
24
star
37

thesis-rails

Thesis: A Rails CMS that doesn't hijack your development workflow. [Deprecated]
Ruby
23
star
38

authority

Next-gen Elixir authentication specification
Elixir
22
star
39

babel-plugin-ignite-ignore-reactotron

Strips Reactotron from production builds for Ignite-based apps.
JavaScript
21
star
40

ChainReactApp2022

TypeScript
20
star
41

react-navx

[Experimental] Navigation and state management in one place for your React Native projects, featuring React Navigation and MobX / MST
TypeScript
20
star
42

mst-reference-pool

MST Reference Pool is a MobX-State-Tree extension that allows you to use references to a pool of model instances in any store.
TypeScript
20
star
43

ProMotion-iap

In-app purchases for ProMotion!
Ruby
19
star
44

ProMotion-form

Deprecated -- use ProMotion-XLForm
Ruby
19
star
45

ignite-maps

Painlessly add react-native-maps to your React Native app using Ignite and Ignite Maps.
EJS
19
star
46

ProMotion-push

Push notification support for ProMotion.
Ruby
18
star
47

rmq-example-app-image-browser

An example app for RubyMotionQuery (rmq). The user can query, browse, and zoom photos. Uses RMQ and AFMotion
Ruby
18
star
48

Parsistence

A nice wrapper for your Parse models on RubyMotion, complete with querying and much more.
Ruby
17
star
49

reactotron-react-js

Reactotron's react-dom client.
TypeScript
16
star
50

whitepotion

WhitePotion is just like RedPotion, but for OS X
Ruby
15
star
51

ProMotion-map

ProMotion::MapScreen gem. Extracted from ProMotion core.
Ruby
13
star
52

react-native-ai

13
star
53

motion-scene-kit

SceneKit stuff in RubyMotion
Ruby
13
star
54

middleman-template

A nice default project template for Middleman, the fantastic static site building tool.
CSS
12
star
55

harvest-invision-integration

Install this User Script via TamperMonkey to add Harvest Tracker to Invision Enterprise workflow pages
JavaScript
12
star
56

authority_ecto

Ecto integration for Authority https://github.com/infinitered/authority
Elixir
12
star
57

rmq-slide-over-control

A RubyMotion RMQ control that places a draggable view over another view, allowing the user to show more or less of the main view below
Ruby
12
star
58

keras-model-zoo

Ready to go, downloadable models for Keras
11
star
59

ignite-json-server

Ignite plugin that adds json-server to an Ignited project
JavaScript
10
star
60

reactotron-redux

The redux plugin for reactotron that allows tracking redux actions and state
TypeScript
10
star
61

reactotron-redux-saga

The redux saga plugin for reactotron. Allows for tracking of Redux Sagas
TypeScript
10
star
62

reactotron-core-client

The core client for all reactotron clients
TypeScript
10
star
63

ignite-redux-persist

An Ignite CLI plugin for Redux Persist
JavaScript
9
star
64

addon-storyshots

JavaScript
8
star
65

rmq-template

A template for RubyMotionQuery projects
Ruby
8
star
66

DiveIntoNative

Just scratching the surface of jumping into Native
Objective-C
7
star
67

ignite-dev-screens

Ignite DevScreens plugin for ignite-cli
JavaScript
7
star
68

tensorplayground

Playground for visual tensors and interactive code
JavaScript
7
star
69

mithril_pubsub

A PubSub layer for Mithril-architected apps
Elixir
6
star
70

ignite-animatable

An ignite plugin for react-native-animatable.
JavaScript
6
star
71

reactotron-core-server

The core reactotron server used by the reactotron app
TypeScript
6
star
72

redpotion-template

Ruby
5
star
73

bluepotion-template

Ruby
5
star
74

ignite-vector-icons

An ignite plugin for `react-native-vector-icons`.
JavaScript
5
star
75

jest-preset-ignite

Glues together TypeScript, React Native, and Jest.
JavaScript
5
star
76

ignite-redux-devtools

An Ignite CLI plugin for Redux DevTools
JavaScript
5
star
77

reactotron-mst

Reactotron's mobx-state-tree plugin
TypeScript
4
star
78

ignite-i18n

An ignite plugin for react-native-i18n.
JavaScript
4
star
79

reactotron-core-ui

TypeScript
4
star
80

ueberauth_dwolla

Ueberauth Plugin for OAuth through Dwolla
Elixir
3
star
81

ups

Address validation/normalization against UPS API
Elixir
3
star
82

ignite-ir-boilerplate

Boilerplate Index
3
star
83

whack-a-mole

A game to demonstrate lists, lifecycle methods, and fundamentals of React Native
JavaScript
3
star
84

tutorial-movie

A demo CLI app, powered by Gluegun
TypeScript
3
star
85

ignite-next-js

Ignite Next.js website boilerplate with Next.js, MySQL, and Github authentication
JavaScript
3
star
86

elavon-elixir

Native elixir client for USBank Elavon Converge API
Elixir
3
star
87

ignite-plugins

The Official Ignite Plugin Registry
3
star
88

eversign

Elixir wrapper for Eversign API
Elixir
2
star
89

MarqueeMark

Large text displayer.
Objective-C
2
star
90

reactotron-apisauce

Reactotron's apisauce plugin
TypeScript
2
star
91

msterymeat

mobx-state-tree proclivities
TypeScript
2
star
92

motion-conf

motion-conf is an easy to use configuration class generator for your RubyMotion apps.
Ruby
2
star
93

wpf-base

Base React Native Windows WPF project for bare bones use in upstream
C#
2
star
94

mobx-forge

TypeScript
2
star
95

cr-2024-intermediate-workshop-lessons

TypeScript
2
star
96

cr-2024-intermediate-workshop-template

TypeScript
2
star
97

orb-publish-docs

CircleCI Orb for publishing docs
Shell
1
star
98

TrainingAppDec2018

What we covered in the online Infinite Red Academy training on December 12, 2018
JavaScript
1
star
99

rmq-plugin-template

Template Repo for RMQ
HTML
1
star
100

solidarity-stacks

Community Solidarity files for well known software stacks
1
star