mirror of
https://github.com/vran-dev/obsidian-contribution-graph.git
synced 2026-07-22 09:20:23 +00:00
feat: support resize cell height and width (#55)
This commit is contained in:
parent
6d6f582593
commit
a985b8a99d
10 changed files with 198 additions and 26 deletions
|
|
@ -1,6 +1,9 @@
|
|||
import { Local } from "./types";
|
||||
|
||||
export class En implements Local {
|
||||
default = "default";
|
||||
click_to_reset = "click to reset";
|
||||
|
||||
/**
|
||||
* context menu
|
||||
*/
|
||||
|
|
@ -13,8 +16,8 @@ export class En implements Local {
|
|||
form_style_settings = "Style Settings";
|
||||
form_about = "About";
|
||||
form_contact_me = "Contact me";
|
||||
form_project_url = "Project";
|
||||
form_sponsor = "Sponsor";
|
||||
form_project_url = "Project";
|
||||
form_sponsor = "Sponsor";
|
||||
form_title = "Title";
|
||||
form_title_placeholder = "Input title";
|
||||
form_graph_type = "Graph Type";
|
||||
|
|
@ -24,7 +27,7 @@ export class En implements Local {
|
|||
form_date_range = "Date Range";
|
||||
form_date_range_latest_days = "Latest Days";
|
||||
form_date_range_latest_month = "Latest Whole Month";
|
||||
form_date_range_latest_year = "Latest Whole Year";
|
||||
form_date_range_latest_year = "Latest Whole Year";
|
||||
form_date_range_latest_days_placeholder = "Input days";
|
||||
form_date_range_fixed_date = "Fixed Date";
|
||||
form_date_range_start_date = "Start Date";
|
||||
|
|
@ -78,15 +81,17 @@ export class En implements Local {
|
|||
form_count_field_count_field_type_task_prop = "Task Property";
|
||||
form_title_font_size_label = "Title font Size";
|
||||
form_number_input_min_warning = "allow min value is {value}";
|
||||
form_number_input_max_warning = "allow max value is {value}";
|
||||
form_number_input_max_warning = "allow max value is {value}";
|
||||
form_fill_the_screen_label = "Fill The Screen";
|
||||
form_main_container_bg_color = "Background Color";
|
||||
form_enable_main_container_shadow = "Enable Shadow";
|
||||
form_enable_main_container_shadow = "Enable Shadow";
|
||||
form_show_cell_indicators = "Show Cell Indicators";
|
||||
form_cell_shape = "Cell Shape";
|
||||
form_cell_shape_circle = "Circle";
|
||||
form_cell_shape_square = "Square";
|
||||
form_cell_shape_rounded = "Rounded";
|
||||
form_cell_min_height = "Min Height";
|
||||
form_cell_min_width = "Min Width";
|
||||
|
||||
form_datasource_type_page = "Page";
|
||||
form_datasource_type_all_task = "All Task";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
|
||||
export interface Local {
|
||||
|
||||
default: string;
|
||||
click_to_reset: string;
|
||||
/**
|
||||
* context menu
|
||||
*/
|
||||
|
|
@ -84,6 +87,8 @@ export interface Local {
|
|||
form_cell_shape_circle: string;
|
||||
form_cell_shape_square: string;
|
||||
form_cell_shape_rounded: string;
|
||||
form_cell_min_height: string;
|
||||
form_cell_min_width: string;
|
||||
|
||||
form_datasource_type_page: string;
|
||||
form_datasource_type_all_task: string;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { Local } from "./types";
|
||||
|
||||
export class Zh implements Local {
|
||||
default = "默认";
|
||||
click_to_reset = "点击重置";
|
||||
/**
|
||||
* context menu
|
||||
*/
|
||||
|
|
@ -86,6 +88,8 @@ export class Zh implements Local {
|
|||
form_cell_shape_circle = "圆形";
|
||||
form_cell_shape_square = "方块";
|
||||
form_cell_shape_rounded = "圆角";
|
||||
form_cell_min_height = "单元格最小高度";
|
||||
form_cell_min_width = "单元格最小宽度";
|
||||
|
||||
form_datasource_type_page = "文档";
|
||||
form_datasource_type_all_task = "所有任务";
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export class CalendarGraphRender extends BaseGraphRender {
|
|||
|
||||
this.renderCellRuleIndicator(graphConfig, main);
|
||||
|
||||
const activityContainer= this.renderActivityContainer(graphConfig, main);
|
||||
const activityContainer = this.renderActivityContainer(graphConfig, main);
|
||||
|
||||
const contributionData = this.generateContributionData(
|
||||
graphConfig
|
||||
|
|
@ -130,6 +130,7 @@ export class CalendarGraphRender extends BaseGraphRender {
|
|||
for (let i = 0; i < 7; i++) {
|
||||
const dateIndicatorCell = document.createElement("div");
|
||||
dateIndicatorCell.className = "cell week-indicator";
|
||||
this.applyCellGlobalStylePartial(dateIndicatorCell, graphConfig, ['minWidth', 'minHeight']);
|
||||
const weekText = localizedWeekDayMapping(
|
||||
((graphConfig.startOfWeek || 0) + 7 + i) % 7,
|
||||
2
|
||||
|
|
@ -150,6 +151,7 @@ export class CalendarGraphRender extends BaseGraphRender {
|
|||
for (let j = 0; j < distance; j++) {
|
||||
const cellEl = document.createElement("div");
|
||||
cellEl.className = "cell";
|
||||
this.applyCellGlobalStylePartial(cellEl, graphConfig, ['minWidth', 'minHeight']);
|
||||
rowContainer?.appendChild(cellEl);
|
||||
}
|
||||
}
|
||||
|
|
@ -170,6 +172,7 @@ export class CalendarGraphRender extends BaseGraphRender {
|
|||
if (item.date == "$HOLE$") {
|
||||
cellEl.innerText = "···";
|
||||
cellEl.className = "cell";
|
||||
this.applyCellGlobalStylePartial(cellEl, graphConfig, ['minWidth', 'minHeight']);
|
||||
} else if (item.value == 0) {
|
||||
cellEl.className = "cell empty";
|
||||
this.applyCellGlobalStyle(cellEl, graphConfig);
|
||||
|
|
@ -194,6 +197,7 @@ export class CalendarGraphRender extends BaseGraphRender {
|
|||
for (let j = 0; j < distance; j++) {
|
||||
const cellEl = document.createElement("div");
|
||||
cellEl.className = "cell";
|
||||
this.applyCellGlobalStylePartial(cellEl, graphConfig, ['minWidth', 'minHeight']);
|
||||
rowContainer?.appendChild(cellEl);
|
||||
}
|
||||
}
|
||||
|
|
@ -205,6 +209,7 @@ export class CalendarGraphRender extends BaseGraphRender {
|
|||
for (let j = 0; j < distance; j++) {
|
||||
const cellEl = document.createElement("div");
|
||||
cellEl.className = "cell";
|
||||
this.applyCellGlobalStylePartial(cellEl, graphConfig, ['minWidth', 'minHeight']);
|
||||
rowContainer?.appendChild(cellEl);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ export class GitStyleTrackGraphRender extends BaseGraphRender {
|
|||
this.bindCellAttribute(cellEl, contributionItem);
|
||||
} else {
|
||||
cellEl.className = "cell";
|
||||
this.applyCellGlobalStylePartial(cellEl, graphConfig, ['minWidth', 'minHeight']);
|
||||
}
|
||||
} else {
|
||||
cellEl.className = "cell";
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export interface GraphRender {
|
|||
}
|
||||
|
||||
export abstract class BaseGraphRender implements GraphRender {
|
||||
constructor() {}
|
||||
constructor() { }
|
||||
|
||||
render(container: HTMLElement, graphConfig: ContributionGraphConfig): void {
|
||||
throw new Error("Method not implemented.");
|
||||
|
|
@ -221,9 +221,8 @@ export abstract class BaseGraphRender implements GraphRender {
|
|||
contributionItem: ContributionCellData,
|
||||
contributionMapByYearMonth: Map<string, number>
|
||||
) {
|
||||
const yearMonth = `${contributionItem.year}-${
|
||||
contributionItem.month + 1
|
||||
}`;
|
||||
const yearMonth = `${contributionItem.year}-${contributionItem.month + 1
|
||||
}`;
|
||||
const yearMonthValue = contributionMapByYearMonth.get(yearMonth) || 0;
|
||||
// tips event
|
||||
setTooltip(
|
||||
|
|
@ -241,6 +240,21 @@ export abstract class BaseGraphRender implements GraphRender {
|
|||
}
|
||||
}
|
||||
|
||||
applyCellGlobalStylePartial(
|
||||
cellEl: HTMLElement,
|
||||
graphConfig: ContributionGraphConfig,
|
||||
props: string[]
|
||||
) {
|
||||
if (graphConfig.cellStyle) {
|
||||
const partialStyle = props.reduce((acc, cur) => {
|
||||
// @ts-ignore
|
||||
acc[cur] = graphConfig.cellStyle[cur];
|
||||
return acc;
|
||||
}, {});
|
||||
Object.assign(cellEl.style, partialStyle);
|
||||
}
|
||||
}
|
||||
|
||||
applyCellStyleRule(
|
||||
cellEl: HTMLElement,
|
||||
contributionItem: ContributionCellData,
|
||||
|
|
|
|||
|
|
@ -46,10 +46,10 @@ export class MonthTrackGraphRender extends BaseGraphRender {
|
|||
text: "",
|
||||
})
|
||||
);
|
||||
this.renderMonthDateIndicator(dateIndicatorRow);
|
||||
this.renderMonthDateIndicator(dateIndicatorRow, graphConfig);
|
||||
|
||||
const activityContainer = this.renderActivityContainer(graphConfig, main);
|
||||
|
||||
const activityContainer= this.renderActivityContainer(graphConfig, main);
|
||||
|
||||
const contributionData = this.generateContributionData(
|
||||
graphConfig
|
||||
).filter((item) => item.date != "$HOLE$");
|
||||
|
|
@ -75,6 +75,7 @@ export class MonthTrackGraphRender extends BaseGraphRender {
|
|||
for (let j = 0; j < fillMax; j++) {
|
||||
const cellEl = document.createElement("div");
|
||||
cellEl.className = "cell";
|
||||
this.applyCellGlobalStylePartial(cellEl, graphConfig, ['minWidth', 'minHeight']);
|
||||
monthDataRowEl?.appendChild(cellEl);
|
||||
}
|
||||
}
|
||||
|
|
@ -91,9 +92,9 @@ export class MonthTrackGraphRender extends BaseGraphRender {
|
|||
monthIndicator.innerText =
|
||||
contributionItem.month == 0
|
||||
? localizedYearMonthMapping(
|
||||
contributionItem.year,
|
||||
contributionItem.month
|
||||
)
|
||||
contributionItem.year,
|
||||
contributionItem.month
|
||||
)
|
||||
: localizedMonthMapping(contributionItem.month);
|
||||
|
||||
this.bindMonthTips(
|
||||
|
|
@ -112,6 +113,7 @@ export class MonthTrackGraphRender extends BaseGraphRender {
|
|||
const cellEl = document.createElement("div");
|
||||
cellEl.className = "cell";
|
||||
cellEl.innerText = "···";
|
||||
this.applyCellGlobalStylePartial(cellEl, graphConfig, ['minWidth', 'minHeight']);
|
||||
monthDataRowEl?.appendChild(cellEl);
|
||||
}
|
||||
}
|
||||
|
|
@ -141,15 +143,17 @@ export class MonthTrackGraphRender extends BaseGraphRender {
|
|||
for (let j = 0; j < fillMax; j++) {
|
||||
const cellEl = document.createElement("div");
|
||||
cellEl.className = "cell";
|
||||
this.applyCellGlobalStylePartial(cellEl, graphConfig, ['minWidth', 'minHeight']);
|
||||
monthDataRowEl?.appendChild(cellEl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderMonthDateIndicator(dateIndicatorRow: HTMLDivElement) {
|
||||
renderMonthDateIndicator(dateIndicatorRow: HTMLDivElement, graphConfig: ContributionGraphConfig) {
|
||||
for (let i = 0; i < 31; i++) {
|
||||
const dateIndicatorCell = document.createElement("div");
|
||||
dateIndicatorCell.className = "cell date-indicator";
|
||||
this.applyCellGlobalStylePartial(dateIndicatorCell, graphConfig, ['minWidth', 'minHeight']);
|
||||
dateIndicatorCell.innerText = `${i + 1}`;
|
||||
dateIndicatorRow.appendChild(dateIndicatorCell);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import NumberInput from "../number-input";
|
|||
import { ColorPicker } from "./ColorPicker";
|
||||
import { About } from "../about";
|
||||
|
||||
export function CreateContributionGraphForm(props: {
|
||||
export function GraphForm(props: {
|
||||
yamlConfig: YamlGraphConfig;
|
||||
onSubmit: (yamlGraphConfig: YamlGraphConfig) => void;
|
||||
app: App;
|
||||
|
|
@ -113,6 +113,17 @@ export function CreateContributionGraphForm(props: {
|
|||
return 16;
|
||||
};
|
||||
|
||||
const parseNumberFromPrefix = (
|
||||
str: string | undefined,
|
||||
defaultValue: number
|
||||
): number => {
|
||||
if (!str) {
|
||||
return 0;
|
||||
}
|
||||
const numberStr = str.replace(/[^0-9]/, "") || "0";
|
||||
return parseInt(numberStr);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tab
|
||||
|
|
@ -515,6 +526,97 @@ export function CreateContributionGraphForm(props: {
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-item">
|
||||
<span className="label">
|
||||
{local.form_cell_min_width}
|
||||
</span>
|
||||
<div className="form-content">
|
||||
<input
|
||||
type="range"
|
||||
min={4}
|
||||
max={64}
|
||||
defaultValue={parseNumberFromPrefix(
|
||||
formData.cellStyle
|
||||
?.minWidth,
|
||||
8
|
||||
)}
|
||||
onChange={(e) => {
|
||||
changeFormData(
|
||||
"cellStyle",
|
||||
{
|
||||
...formData.cellStyle,
|
||||
minWidth:
|
||||
e.target.value +
|
||||
"px",
|
||||
}
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
className="input-range-value-label"
|
||||
onClick={(e) => {
|
||||
changeFormData(
|
||||
"cellStyle",
|
||||
{
|
||||
...formData.cellStyle,
|
||||
minWidth: undefined,
|
||||
}
|
||||
);
|
||||
}}
|
||||
>
|
||||
{formData.cellStyle?.minWidth
|
||||
? formData.cellStyle
|
||||
?.minWidth
|
||||
: local.default}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-item">
|
||||
<span className="label">
|
||||
{local.form_cell_min_height}
|
||||
</span>
|
||||
<div className="form-content">
|
||||
<input
|
||||
type="range"
|
||||
min={4}
|
||||
max={64}
|
||||
defaultValue={parseNumberFromPrefix(
|
||||
formData.cellStyle
|
||||
?.minHeight,
|
||||
8
|
||||
)}
|
||||
onChange={(e) => {
|
||||
changeFormData(
|
||||
"cellStyle",
|
||||
{
|
||||
...formData.cellStyle,
|
||||
minHeight:
|
||||
e.target.value +
|
||||
"px",
|
||||
}
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
className="input-range-value-label"
|
||||
onClick={(e) => {
|
||||
changeFormData(
|
||||
"cellStyle",
|
||||
{
|
||||
...formData.cellStyle,
|
||||
minHeight:
|
||||
undefined,
|
||||
}
|
||||
);
|
||||
}}
|
||||
>
|
||||
{formData.cellStyle?.minHeight
|
||||
? formData.cellStyle
|
||||
?.minHeight
|
||||
: local.default}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-item">
|
||||
<span className="label">
|
||||
{local.form_theme}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Modal, App, MarkdownView, parseYaml, stringifyYaml } from "obsidian";
|
||||
import { StrictMode } from "react";
|
||||
import { Root, createRoot } from "react-dom/client";
|
||||
import { CreateContributionGraphForm } from "./GraphForm";
|
||||
import { GraphForm } from "./GraphForm";
|
||||
import { YamlGraphConfig } from "src/processor/types";
|
||||
import { YamlConfigReconciler } from "src/processor/yamlConfigReconciler";
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ export class ContributionGraphCreateModal extends Modal {
|
|||
this.root = createRoot(rootContainer);
|
||||
this.root.render(
|
||||
<StrictMode>
|
||||
<CreateContributionGraphForm
|
||||
<GraphForm
|
||||
yamlConfig={yamlConfig}
|
||||
onSubmit={onSubmit}
|
||||
app={this.app}
|
||||
|
|
|
|||
44
styles.css
44
styles.css
|
|
@ -64,7 +64,6 @@
|
|||
align-items: flex-start;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
|
||||
}
|
||||
|
||||
.contribution-graph .main .charts.default .column {
|
||||
|
|
@ -215,7 +214,11 @@
|
|||
justify-content: center;
|
||||
}
|
||||
|
||||
.contribution-graph .calendar .month-container .week-indicator-container .cell.week-indicator {
|
||||
.contribution-graph
|
||||
.calendar
|
||||
.month-container
|
||||
.week-indicator-container
|
||||
.cell.week-indicator {
|
||||
font-size: 0.6rem;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
|
|
@ -402,7 +405,10 @@
|
|||
gap: 8px;
|
||||
}
|
||||
|
||||
.contribution-graph-modal-form .form-item .form-vertical-content>input[type="text"] {
|
||||
.contribution-graph-modal-form
|
||||
.form-item
|
||||
.form-vertical-content
|
||||
> input[type="text"] {
|
||||
flex-grow: 1;
|
||||
border-width: 0px 0px 1px 0px;
|
||||
padding: 3px;
|
||||
|
|
@ -839,13 +845,22 @@
|
|||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.contribution-graph .activity-container .activity-content .activity-list .activity-item {
|
||||
.contribution-graph
|
||||
.activity-container
|
||||
.activity-content
|
||||
.activity-list
|
||||
.activity-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.contribution-graph .activity-container .activity-content .activity-list .activity-item .label {
|
||||
.contribution-graph
|
||||
.activity-container
|
||||
.activity-content
|
||||
.activity-list
|
||||
.activity-item
|
||||
.label {
|
||||
color: var(--text-muted);
|
||||
padding: 0.4rem 0.6rem;
|
||||
}
|
||||
|
|
@ -858,7 +873,11 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.contribution-graph .activity-container .activity-content .activity-navigation a {
|
||||
.contribution-graph
|
||||
.activity-container
|
||||
.activity-content
|
||||
.activity-navigation
|
||||
a {
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
padding: 0.4rem 0.6rem;
|
||||
|
|
@ -905,4 +924,17 @@
|
|||
.about-container .about-item img {
|
||||
max-width: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.input-range-value-label {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.input-range-value-label:hover {
|
||||
background: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
Loading…
Reference in a new issue