diff --git a/README.md b/README.md
index 61b04b7..690f436 100644
--- a/README.md
+++ b/README.md
@@ -4,12 +4,14 @@
# Obsidian Strava Sync
-This plugin syncs activities from [Strava](https://www.strava.com/) into [Obsidian](https://obsidian.md).
+This plugin syncronizes activities from [Strava](https://www.strava.com/) into [Obsidian](https://obsidian.md).
- ποΈ Import [Strava bulk export](https://support.strava.com/hc/en-us/articles/216918437-Exporting-your-Data-and-Bulk-Export#h_01GG58HC4F1BGQ9PQZZVANN6WF) CSV files for historical activities
- π
Sync recent activities from Strava via the [Strava API](https://developers.strava.com/docs/reference/#api-Activities-getLoggedInAthleteActivities)
- π [Handlebars.js](https://handlebarsjs.com/guide/) templates for imported activities
-- πΏ Customizable front matter allowing for [Obsidian Dataview](https://blacksmithgu.github.io/obsidian-dataview/) integration
+- πΏ Customizable properties / front matter allowing for [Obsidian Dataview](https://blacksmithgu.github.io/obsidian-dataview/) integration
+
+The purpose of this plugin is not to provide a data backup, or to replace the functionality of the Strava apps. It's simply to allow activities to be more easily referenced, tracked and visualized within Obsidian, for example through integration with the [Dataview](https://blacksmithgu.github.io/obsidian-dataview/) and [Charts](https://charts.phib.ro/Meta/Charts/Charts+Documentation) plugins.
## Examples
@@ -19,7 +21,7 @@ This plugin syncs activities from [Strava](https://www.strava.com/) into [Obsidi
-These are some examples of what can be achieved along with the [Dataview](https://blacksmithgu.github.io/obsidian-dataview/) and [Charts](https://charts.phib.ro/Meta/Charts/Charts+Documentation) plugins.
+These are some examples of what can be achieved along with the [Dataview](https://blacksmithgu.github.io/obsidian-dataview/) and [Charts](https://charts.phib.ro/Meta/Charts/Charts+Documentation) plugins. See the [Dataview Integration](#dataview-integration) section below for more ideas.
## Installation
@@ -27,7 +29,8 @@ This plugin is currently only available for manual installation.
### Manually installing the plugin
-Copy over `main.js`, `styles.css`, `manifest.json` from [the latest release](https://github.com/watsonbox/obsidian-strava-sync/releases) to your vault `VaultFolder/.obsidian/plugins/obsidian-strava-sync/`.
+1. Download the latest release from [the releases page](https://github.com/watsonbox/obsidian-strava-sync/releases).
+2. Copy `main.js`, `styles.css`, and `manifest.json` to your vault's `VaultFolder/.obsidian/plugins/obsidian-strava-sync/` directory.
### Sync Configuration
@@ -37,6 +40,194 @@ In order to configure the plugin, you will need to obtain an access token from S
Once that's done, copy the Client ID and Client Secret into the plugin settings, and click "Connect with Strava". You will be redirected to Strava to login and authorize access. After successful authorization, you will be redirected back to your Obsidian vault and can close the browser window.
+## Basic Usage
+
+Typically, once the plugin is enabled and configured, you'll want to set up templates for the activities as you import them. This can be done for the file path, the content itself, and the properties to be added.
+
+### Templating
+
+The default file path template is `Strava/{{start_date}}/{{id}} {{name}}`, which will create a folder for each day, and a file for each activity within that folder for example `Strava/2024-02-20/1234567890 Running with the bears.md`.
+
+The date formats themselves can also be adjusted in the plugin settings.
+
+#### Content
+
+The default content template is:
+
+```markdown
+# {{name}}
+
+[https://www.strava.com/activities/{{id}}](https://www.strava.com/activities/{{id}})
+{{#if description}}
+
+Description: {{description}}
+{{/if}}
+{{#if private_note}}
+
+> [!NOTE] Private note
+> {{private_note}}
+{{/if}}
+
+#Strava
+```
+
+This will produce a file similar to the following:
+
+```markdown
+# Running with the bears
+
+[https://www.strava.com/activities/1234567890](https://www.strava.com/activities/1234567890)
+
+Description: This is a description
+
+> [!NOTE] Private note
+> This is a private note
+```
+
+The templating language used is [Handlebars.js](https://handlebarsjs.com/guide/). The available fields are as follows (more info [here](https://developers.strava.com/docs/reference/#api-models-DetailedActivity)):
+
+| Field | Example(s) | Description |
+|-----------------------|-----------------------------------|--------------------------------------------|
+| `id` | 1218940553 | Unique identifier for the activity |
+| `start_date` | "2024-08-28 05:07:43" | Start date and time of the activity |
+| `name` | "Dynamo Challenge 2024" | Name of the activity |
+| `sport_type` | "Ride", "Run", "Swim", etc. | Type of sport |
+| `description` | "Great weather and company" | Description of the activity |
+| `private_note` | "Take two inner tubes next time" | Private note for the activity |
+| `elapsed_time` | 38846 | Total elapsed time in seconds |
+| `moving_time` | 26010 | Moving time in seconds |
+| `distance` | 154081.0 | Distance in meters |
+| `max_heart_rate` | 180 | Maximum heart rate |
+| `max_speed` | 18.8 | Maximum speed in meters per second |
+| `average_speed` | 11.1 | Average speed in meters per second |
+| `total_elevation_gain`| 1338.0 | Total elevation gain in meters |
+| `elev_low` | 50.7 | Lowest elevation in meters |
+| `elev_high` | 60.2 | Highest elevation in meters |
+| `calories` | 1234 | Calories burned |
+| `icon` | π΄ββοΈππβ·οΈπΈπΆποΈπΆπ΅β³π¦½π₯Ύ
βΈοΈπΌπππ§π§π£β΅πΉπβ½πΎ | Activity icon |
+
+#### Properties
+
+Finally, you can also specify any of these fields to be added to the [properties](https://help.obsidian.md/Editing+and+formatting/Properties) / front matter of each imported activity. By default the properties are `name`, `start_date`, `sport_type`, `description`, `private_note`, `elapsed_time`, `moving_time`, `distance`, and `icon`, for example:
+
+```
+---
+id: 1014355555
+name: Evening Run
+start_date: 2024-06-02T18:31:27.000Z
+sport_type: Run
+distance: 4372.5
+elapsed_time: 1651
+moving_time: 1511
+description: "Great run"
+private_note: "Push it to 10km next time"
+icon: π
+---
+```
+
+The property `id` is always added.
+
+### Importing Recent Activities
+
+Next, either by clicking the Strava icon in the [ribbon](https://help.obsidian.md/User+interface/Ribbon) or using the command "Import new activities from Strava", the plugin will fetch and import your 30 most recent activities from Strava using the API.
+
+Each time new activities are imported, the start date of the last imported activity is saved. Next time you import new activities, only activities after that date will be imported.
+
+### Importing a Strava Bulk Export
+
+Strava allows you to download your activities as a bulk export as described [here](https://support.strava.com/hc/en-us/articles/216918437-Exporting-your-Data-and-Bulk-Export#h_01GG58HC4F1BGQ9PQZZVANN6WF). This export contains all historical activities. Either in the plugin settings, or by using the "Import Strava activities from bulk export CSV" command directly, you can select the `activities.csv` file from the bulk export to import the entire history.
+
+> [!NOTE]
+> Note that the [Strava bulk export CSV format](./assets/activities.csv) is not the same as the [Web API activity format (JSON)](./assets/activity_12271989718.json). This plugin allows both formats to be imported, but some fields that are not common to both formats are not imported.
+
+> [!TIP]
+> You may prefer to exclude imported activities from the Obsidian search and graph views by adding the sync folder to "Options -> Files and linkes -> Excluded files" in the settings.
+
+## Dataview Integration
+
+Once you've selected the activity attributes you'd like to include as properties, the real power of this plugin comes from the Dataview integration. You can install it through the Community Plugins tab in Obsidian, and then refer to the detailed [documentation](https://blacksmithgu.github.io/obsidian-dataview/) to learn how to use it.
+
+The following are some examples of what you can do with Dataview and the Strava plugin.
+
+### List all activities with "knee" in private note
+
+ ```dataview
+ TABLE WITHOUT id name, dateformat(start_date, "yyyy-MM-dd") AS date, private_note
+ FROM "Apps/Strava"
+ WHERE icontains(private_note, "knee")
+ ```
+
+### List all activities for the current month in a callout
+
+ > [!EXAMPLE] This Month's Activities
+ >
+ > ```dataview
+ > TABLE WITHOUT id
+ > link(file.path, name) AS Activity,
+ > dateformat(localtime(start_date), "yyyy-MM-dd") AS Date,
+ > dur(round(elapsed_time/60) + "m") as Duration,
+ > choice(length(private_note) > 0, "π", "") AS "π",
+ > choice(icontains(private_note, "pain"), "π€", "") AS "π€"
+ > FROM "Strava"
+ > WHERE dateformat(start_date, "yyyy-MM") = dateformat(date(now),"yyyy-MM")
+ > ```
+
+### Show a chart of total distance per year by activity type
+
+Using DataviewJS gives us much more flexibility, for example the ability to use the [Charts](https://charts.phib.ro/Meta/Charts/Charts+Documentation) plugin to visualize historical activity data.
+
+ ```dataviewjs
+```js
+const pages = dv.pages('#Strava')
+const dates = pages.map(p => p.start_date).values
+const yearData = {};
+
+pages.forEach(page => {
+ const year = moment(page.start_date.ts).startOf('week').format('YYYY');
+ const ridingDistance = page.sport_type === 'Ride' ? page.distance : 0;
+ const runningDistance = page.sport_type === 'Run' ? page.distance : 0;
+
+ if (!yearData.hasOwnProperty(year)) {
+ yearData[year] = {
+ ridingDistance: 0,
+ runningDistance: 0
+ };
+ }
+
+ yearData[year].ridingDistance += ridingDistance;
+ yearData[year].runningDistance += runningDistance;
+});
+
+const years = Object.keys(yearData);
+const ridingDistance = Object.values(yearData).map(data => data.ridingDistance);
+const runningDistance = Object.values(yearData).map(data => data.runningDistance);
+
+const chartData = {
+ type: 'bar',
+ data: {
+ labels: years,
+ datasets: [
+ {
+ label: 'π΄ Riding distance',
+ data: ridingDistance,
+ backgroundColor: [ 'rgba(255, 99, 132, 0.2)' ],
+ borderColor: [ 'rgba(255, 99, 132, 1)' ],
+ borderWidth: 1
+ },
+ {
+ label: 'π Running distance',
+ data: runningDistance,
+ backgroundColor: [ 'rgba(54, 162, 235, 0.2)' ],
+ borderColor: [ 'rgba(54, 162, 235, 1)' ],
+ borderWidth: 1
+ }
+ ]
+ }
+}
+window.renderChart(chartData, this.container)
+```
+ ```
+
## Development Guidelines
- Clone this repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/obsidian-strava-sync` folder.
@@ -74,8 +265,6 @@ Run `yarn version`, enter a new version number, then push to build and prepare a
- [Strava Developers - API Reference](https://developers.strava.com/docs/reference/)
- [Strava Developers - Getting Started + Auth](https://developers.strava.com/docs/getting-started/)
- [Strava Developers - Rate limiting](https://developers.strava.com/docs/rate-limits/)
-- [Strava Account Data Request](https://www.strava.com/athlete/delete_your_account)
-- [node-strava/node-strava-v3: API wrapper for Strava's v3 API](https://github.com/node-strava/node-strava-v3)
- [Challenges when Testing Plugins | Obsidian Collection](https://www.moritzjung.dev/obsidian-collection/plugin-dev/testing/challengeswhentestingplugins/)
- [Obsidian Dataview](https://blacksmithgu.github.io/obsidian-dataview/)
diff --git a/src/Settings.ts b/src/Settings.ts
index 6699573..7faf53b 100644
--- a/src/Settings.ts
+++ b/src/Settings.ts
@@ -36,7 +36,17 @@ export const DEFAULT_SETTINGS: Settings = {
},
activity: {
contentDateFormat: "yyyy-MM-dd HH:mm:ss",
- frontMatterProperties: [],
+ frontMatterProperties: [
+ "name",
+ "start_date",
+ "sport_type",
+ "description",
+ "private_note",
+ "elapsed_time",
+ "moving_time",
+ "distance",
+ "icon"
+ ],
template: DEFAULT_TEMPLATE
}
}
diff --git a/src/SettingsTab.ts b/src/SettingsTab.ts
index 8980a82..80da525 100644
--- a/src/SettingsTab.ts
+++ b/src/SettingsTab.ts
@@ -195,7 +195,7 @@ export class SettingsTab extends PluginSettingTab {
containerEl.createEl('h3', { text: 'Activity' });
new Setting(containerEl)
- .setName('Front matter')
+ .setName('Properties / Front matter')
.setDesc(
createFragment((fragment) => {
fragment.append(