{"id":15297522,"url":"https://github.com/liuliqiang/flask-theme","last_synced_at":"2025-09-19T18:31:20.688Z","repository":{"id":57430793,"uuid":"72610881","full_name":"liuliqiang/flask-theme","owner":"liuliqiang","description":"A web theme library support for flask","archived":false,"fork":false,"pushed_at":"2023-09-02T09:11:01.000Z","size":83,"stargazers_count":4,"open_issues_count":0,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-30T13:20:42.972Z","etag":null,"topics":["flask","flask-theme","python","python2","python27","python3"],"latest_commit_sha":null,"homepage":"https://flask-theme.readthedocs.io/en/latest/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/liuliqiang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-11-02T06:31:20.000Z","updated_at":"2025-07-01T11:12:26.000Z","dependencies_parsed_at":"2024-10-22T15:12:58.923Z","dependency_job_id":null,"html_url":"https://github.com/liuliqiang/flask-theme","commit_stats":{"total_commits":55,"total_committers":9,"mean_commits":6.111111111111111,"dds":0.6,"last_synced_commit":"f7d87c6bb056ae1c8f7a8d12f090865c643b8219"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/liuliqiang/flask-theme","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liuliqiang%2Fflask-theme","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liuliqiang%2Fflask-theme/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liuliqiang%2Fflask-theme/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liuliqiang%2Fflask-theme/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/liuliqiang","download_url":"https://codeload.github.com/liuliqiang/flask-theme/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liuliqiang%2Fflask-theme/sbom","scorecard":{"id":593620,"data":{"date":"2025-08-11","repo":{"name":"github.com/liuliqiang/flask-theme","commit":"2329f802c40dfece4e196f7e9173015736014391"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.3,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":2,"reason":"Found 5/23 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 12 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-20T22:35:57.893Z","repository_id":57430793,"created_at":"2025-08-20T22:35:57.894Z","updated_at":"2025-08-20T22:35:57.894Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275982494,"owners_count":25564149,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-19T02:00:09.700Z","response_time":108,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flask","flask-theme","python","python2","python27","python3"],"created_at":"2024-09-30T19:18:08.209Z","updated_at":"2025-09-19T18:31:20.642Z","avatar_url":"https://github.com/liuliqiang.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"Flask-Theme[¶](#flask-theme \"Permalink to this headline\")\n=========================================================\n\nFlask-Theme makes it easy for your application to support a wide range of appearances.\n\n*   [Writing Theme](#writing-theme)\n    *   [Writing Templates](#writing-templates)\n    *   [`info.json` Fields](#info-json-fields)\n    *   [Tips for Theme Writers](#tips-for-theme-writers)\n*   [Using Themes in Your Application](#using-themes-in-your-application)\n    *   [Theme Loaders](#theme-loaders)\n    *   [Rendering Templates](#rendering-templates)\n    *   [Selecting Themes](#selecting-themes)\n    *   [Tips for Application Programmers](#tips-for-application-programmers)\n*   [API Documentation](#api-documentation)\n    *   [Loading Themes](#loading-themes)\n*   [Thanks To](#thanks-to)\n\nWriting Theme[¶](#writing-theme \"Permalink to this headline\")\n-------------------------------------------------------------\n\nA theme is simply a folder containing static media (like CSS files, images, and JavaScript) and Jinja2 templates, with some metadata. A theme folder should look something like this:\n\n```\nmy_theme/\n    info.json\n    license.txt\n    templates/\n        layout.html\n        index.html\n    static/\n        style.css\n```\n\nThe `info.json` file contains the theme’s metadata, so that the application can provide a nice switching interface if necessary. `license.txt` is optional and contains the full text of the theme’s license. `static` is served directly to clients, and `templates` contains the Jinja2 template files.\n\nNote that exactly what templates you need to create will vary between applications. Check the application’s docs (or source code) to see what you need.\n\n### Writing Templates[¶](#writing-templates \"Permalink to this headline\")\n\nFlask uses the Jinja2 template engine, so you should read [its documentation](http://jinja.pocoo.org/2/documentation/templates) to learn about the actual syntax of the templates.\n\nAll templates loaded from a theme will have a global function named `theme` available to look up the theme’s templates. For example, if you want to extend, import, or include another template from your theme, you can use `theme(template_name)`, like this:\n\n```\n{% extends theme('layout.html') %}\n{% from theme('_helpers.html') import form_field %}\n```\n\nIf the template you requested doesn’t exist within the theme, it will fall back to using the application’s template. If you pass `false` as the second parameter, it will only return the theme’s template.\n\n```\n{% include theme('header.html', false) %}\n```\n\nYou can still import/include templates from the application, though. Just use the tag without calling `theme`.\n\n```\n{% from '_helpers.html' import link_to %}\n{% include '_jquery.html' %}\n```\n\nYou can also get the URL for the theme’s media files with the `theme_static` function:\n\n```\n\u003clink rel=stylesheet href=\"{{ theme_static('style.css') }}\"\u003e\n```\n\n### `info.json` Fields[¶](#info-json-fields \"Permalink to this headline\")\n\n- `application` : required\n\n    This is the application’s identifier. Exactly what identifier you need to use varies between applications.\n\n- `identifier` : required\n\n    The theme’s identifier. It should be a Python identifier (starts with a letter or underscore, the rest can be letters, underscores, or numbers) and should match the name of the theme’s folder.\n\n- `name` : required\n\n    A human-readable name for the theme.\n\n- `author` : required\n\n    The name of the theme’s author, that is, you. It does not have to include an e-mail address, and should be displayed verbatim.\n\n- `description`\n\n    A description of the theme in a few sentences. If you can write multiple languages, you can include additional fields in the form `description_lc`, where `lc` is a two-letter language code like `es` or `de`. They should contain the description, but in the indicated language.\n\n- `website`\n\n    The URL of the theme’s Web site. This can be a Web site specifically for this theme, Web site for a collection of themes that includes this theme, or just the author’s Web site.\n\n- `license`\n\n    A simple phrase indicating your theme’s license, like `GPL`, `MIT/X11`, `Public Domain`, or `Creative Commons BY-SA 3.0`. You can put the full license’s text in the `license.txt` file.\n\n- `license_url`\n\n    If you don’t want to include the full text in the `license.txt` file, you can include a URL for a Web site where the text can be viewed. This is good for long licenses like the GPL or Creative Commons licenses.\n\n- `preview`\n\n    A preview image for the theme. This should be the filename for an image within the `static` directory.\n\n- `doctype`\n\n    The version of HTML used by the theme. It can be `html4`, `html5`, or `xhtml`. The application can use this to do things like switch the output format of a markup generator. (The default if this is left out is `html5` to be safe. HTML5 is used by the majority of Flask users, so it’s best to use it.)\n\n- `options`\n\n    If this is given, it should be a dictionary (object in JSON parlance) containing application-specific options. You will need to check the application’s docs to see what options it uses. (For example, an application like a pastebin or wiki that highlights source code may want the theme to specify a default [Pygments](http://pygments.org/) style in the options.)\n\n### Tips for Theme Writers[¶](#tips-for-theme-writers \"Permalink to this headline\")\n\n*   Always specify a doctype.\n*   Remember that you have to use double-quotes with strings in JSON.\n*   Look at the non-theme templates provided with the application. See how they interact.\n*   Remember that most of the time, you can alter the application’s appearance completely just by changing the layout template and the style.\n\nUsing Themes in Your Application[¶](#using-themes-in-your-application \"Permalink to this headline\")\n---------------------------------------------------------------------------------------------------\n\nTo set up your application to use themes, you need to use the `setup_themes` function. It doesn’t rely on your application already being configured, so you can call it whenever is convenient. It does three things:\n\n*   Adds a `ThemeManager` instance to your application as `app.theme_manager`.\n*   Registers the `theme` and `theme_static` globals with the Jinja2 environment.\n*   Registers the `_themes` module or blueprint (depending on the Flask version) to your application, by default with the URL prefix `/_themes` (you can change it).\n\nWarning\n\nSince the “Blueprints” mechanism of Flask 0.7 causes headaches in module compatibility mode, `setup_themes` will automatically register `_themes` as a blueprint and not as a module if possible. If this causes headaches with your application, then you need to either (a) upgrade to Flask 0.7 or (b) set `Flask\u003c0.7` in your requirements.txt file.\n\n### Theme Loaders[¶](#theme-loaders \"Permalink to this headline\")\n\n`setup_themes` takes a few arguments, but the one you will probably be using most is `loaders`, which is a list of theme loaders to use (in order) to find themes. The default theme loaders are:\n\n*   `packaged_themes_loader`, which looks in your application’s `themes` directory for themes (you can use this to ship one or two default themes with your application)\n*   `theme_paths_loader`, which looks at the `THEME_PATHS` configuration setting and loads themes from each folder therein\n\nIt’s easy to write your own loaders, though - a loader is just a callable that takes an application instance and returns an iterable of `Theme` instances. You can use the `load_themes_from` helper function to yield all the valid themes contained within a folder. For example, if your app uses an “instance folder” like [Zine](http://zine.pocoo.org/) that can have a “themes” directory:\n\n```\ndef instance_loader(app):\n    themes_dir = os.path.join(app.instance_root, 'themes')\n    if os.path.isdir(themes_dir):\n        return load_themes_from(themes_dir)\n    else:\n        return ()\n```\n\n### Rendering Templates[¶](#rendering-templates \"Permalink to this headline\")\n\nOnce you have the themes set up, you can call in to the theme machinery with `render_theme_template`. It works like `render_template`, but takes a `theme` parameter before the template name. Also, `static_file_url` will generate a URL to the given static file.\n\nWhen you call `render_theme_template`, it sets the “active template” to the given theme, even if you have to fall back to rendering the application’s template. That way, if you have a template like `by_year.html` that isn’t defined by the current theme, you can still\n\n*   extend (`{% extends theme('layout.html') %}`)\n*   include (`{% include theme('archive_header.html') %}`)\n*   import (`{% from theme('_helpers.html') import show_post %}`)\n\ntemplates defined by the theme. This way, the theme author doesn’t have to implement every possible template - they can define templates like the layout, and showing posts, and things like that, and the application-provided templates can use those building blocks to form the more complicated pages.\n\n### Selecting Themes[¶](#selecting-themes \"Permalink to this headline\")\n\nHow exactly you select the theme will vary between applications, so Flask-Theme doesn’t make the decision for you. If your app is any larger than a few views, though, you will probably want to provide a helper function that selects the theme based on whatever (settings, logged-in user, page) and renders the template. For example:\n\n```\ndef get_current_theme():\n    if g.user is not None:\n        ident = g.user.theme\n    else:\n        ident = current_app.config.get('DEFAULT_THEME', 'plain')\n    return get_theme(ident)\n\ndef render(template, **context):\n    return render_theme_template(get_current_theme(), template, **context)\n```\n\nWarning\n\nMake sure that you _only_ get `Theme` instances from the theme manager. If you need to create a `Theme` instance manually outside of a theme loader, that’s a sign that you’re doing it wrong. Instead, write a loader that can load that theme and pass it to `setup_themes`, because if the theme is not loaded by the manager, then its templates and static files won’t be available, which will usually lead to your application breaking.\n\n### Tips for Application Programmers[¶](#tips-for-application-programmers \"Permalink to this headline\")\n\n*   Provide default templates, preferably for everything. Use simple, unstyled HTML.\n*   If you find yourself repeating design elements, put them in a macro in a separate template. That way, theme authors can override them more easily.\n*   Put class names or IDs on any elements that the theme author may want to style. (And by that I mean all of them.) That way they won’t have to override the template unnecessarily if all they want to do is right-align the meta information.\n\nAPI Documentation[¶](#api-documentation \"Permalink to this headline\")\n---------------------------------------------------------------------\n\nThis API documentation is automatically generated from the source code.\n\n### Loading Themes[¶](#loading-themes \"Permalink to this headline\")\n\nThanks To[¶](#thanks-to\")\n-------------------------\n\n- [maxcountryman](https://github.com/maxcountryman/flask-themes)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliuliqiang%2Fflask-theme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliuliqiang%2Fflask-theme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliuliqiang%2Fflask-theme/lists"}