-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #29 from hyphacoop/default-list
feat: add conditional custom theme with persistence and defaults.json for default export list
- Loading branch information
Showing
17 changed files
with
437 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,38 @@ | ||
# Social Reader | ||
A P2P and offline-first ActivityPub client for reading and following microblogs on the Fediverse, avoiding dependency on always-online HTTP servers, allowing access to content anytime, anywhere. | ||
|
||
## Customizing Your Community's Reader | ||
|
||
You can easily deploy a customized version of the reader by [forking](https://github.com/hyphacoop/reader.distributed.press/fork) this repository and modifying the `defaults.json` file located in the `./config` folder. This allows you to set the community name, define a custom theme, and specify the default followed actors for your community. | ||
|
||
### Configuration Options: | ||
|
||
- `communityName`: The name of your community, which will appear as the page title and sidebar branding. | ||
- `theme`: Customize the appearance of the reader. You can specify: | ||
- `bgColor`: Background color for the reader. | ||
- `postBgColor`: Background color for individual posts. | ||
- `postDetailsColor`: Color for post details (such as date and metadata). | ||
- `postLinkColor`: Color for links within posts. | ||
- `defaultFollowedActors`: A list of URLs representing the actors that will be followed by default when no actors are followed. | ||
|
||
### Example `defaults.json`: | ||
|
||
```json | ||
{ | ||
"version": "1.2.0", | ||
"communityName": "Akhi's Art Club", | ||
"theme": { | ||
"bgColor": "#ecfeff", | ||
"postBgColor": "#cffafe", | ||
"postDetailsColor": "#06b6d4", | ||
"postLinkColor": "#0ea5e9" | ||
}, | ||
"defaultFollowedActors": [ | ||
"https://mastodon.social/@akhileshthite" | ||
] | ||
} | ||
``` | ||
|
||
![Akhi's Art Club on Social Reader](./custom-demo.png) | ||
|
||
For more information, please visit [docs.distributed.press](https://docs.distributed.press/social-reader). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"version": "1.2.0", | ||
"communityName": "Social Reader", | ||
"theme": { | ||
"bgColor": "#ffffff", | ||
"postBgColor": "#ebf3f5", | ||
"postDetailsColor": "#4d626a", | ||
"postLinkColor": "#0ea5e9" | ||
}, | ||
"defaultFollowedActors": [ | ||
"https://social.distributed.press/v1/@[email protected]/", | ||
"ipns://distributed.press/about.ipns.jsonld", | ||
"hyper://hypha.coop/about.hyper.jsonld", | ||
"https://sutty.nl/about.jsonld" | ||
] | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export const defaultLightTheme = { | ||
bgColor: '#ffffff', | ||
postBgColor: '#ebf3f5', | ||
postDetailsColor: '#4d626a', | ||
postLinkColor: '#0ea5e9' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { db } from './dbInstance.js' | ||
import { defaultLightTheme } from './default-theme.js' | ||
|
||
export async function fetchDefaults () { | ||
try { | ||
const response = await fetch('./config/defaults.json') | ||
if (!response.ok) { | ||
throw new Error('Failed to load defaults.') | ||
} | ||
return await response.json() | ||
} catch (error) { | ||
console.error('Error fetching defaults:', error) | ||
return {} | ||
} | ||
} | ||
|
||
export async function applyDefaults () { | ||
try { | ||
const defaults = await fetchDefaults() | ||
|
||
// Apply community name if available | ||
if (defaults.communityName) { | ||
document.title = defaults.communityName // Update the main title | ||
const brandingElement = document.getElementById('header-branding') // Update sidebar branding | ||
if (brandingElement) { | ||
brandingElement.textContent = defaults.communityName | ||
} | ||
} | ||
|
||
// Check if a theme is already set in the DB | ||
const currentTheme = await db.getTheme() | ||
if (currentTheme) { | ||
// Theme is already set by the user; do not override | ||
return | ||
} | ||
|
||
// Determine if the custom theme differs from the default light theme | ||
const customTheme = defaults.theme || {} | ||
const isCustomDifferent = isThemeDifferent(customTheme, defaultLightTheme) | ||
|
||
// Apply custom theme if available and different | ||
if (isCustomDifferent) { | ||
await db.setTheme('custom') // Set the theme to custom if not already set | ||
applyCustomTheme(customTheme) | ||
} else { | ||
await db.setTheme('light') // Ensure the theme is set to light | ||
applyTheme('light') | ||
} | ||
} catch (error) { | ||
console.error('Error applying defaults:', error) | ||
} | ||
} | ||
|
||
function isThemeDifferent (custom, defaultTheme) { | ||
// Compare each property; return true if any property differs | ||
for (const key in defaultTheme) { | ||
if (custom[key] !== defaultTheme[key]) { | ||
return true | ||
} | ||
} | ||
// Additionally, check if custom has extra properties | ||
for (const key in custom) { | ||
if (!(key in defaultTheme)) { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
function applyTheme (themeName) { | ||
const root = document.documentElement | ||
root.setAttribute('data-theme', themeName) | ||
} | ||
|
||
async function applyCustomTheme (theme) { | ||
const root = document.documentElement | ||
root.setAttribute('data-theme', 'custom') | ||
|
||
// Create or update a <style id="custom-theme"> element | ||
let styleEl = document.getElementById('custom-theme') | ||
if (!styleEl) { | ||
styleEl = document.createElement('style') | ||
styleEl.id = 'custom-theme' | ||
document.head.appendChild(styleEl) | ||
} | ||
|
||
const themeVars = [] | ||
|
||
if (theme.bgColor) themeVars.push(` --bg-color: ${theme.bgColor};`) | ||
if (theme.postBgColor) themeVars.push(` --rdp-bg-color: ${theme.postBgColor};`) | ||
if (theme.postDetailsColor) themeVars.push(` --rdp-details-color: ${theme.postDetailsColor};`) | ||
if (theme.postLinkColor) themeVars.push(` --rdp-link-color: ${theme.postLinkColor};`) | ||
|
||
styleEl.textContent = ` | ||
:root[data-theme="custom"] { | ||
${themeVars.join('\n')} | ||
} | ||
` | ||
} | ||
|
||
export async function initializeDefaultFollowedActors () { | ||
const hasFollowedActors = await db.hasFollowedActors() | ||
|
||
if (!hasFollowedActors) { | ||
try { | ||
const defaults = await fetchDefaults() | ||
const defaultActors = defaults.defaultFollowedActors || [] | ||
|
||
// Follow default actors from the loaded configuration | ||
await Promise.all(defaultActors.map((actorUrl) => db.followActor(actorUrl))) | ||
} catch (error) { | ||
console.error('Error loading default followed actors: ', error) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.